[entropy.services] goodbye old and ugly RPC service, R.I.P.

This commit is contained in:
Fabio Erculiani
2011-04-14 15:17:54 +02:00
parent e5bf7e039d
commit 80dfbcc0f2
26 changed files with 1 additions and 9433 deletions
+1 -6
View File
@@ -25,11 +25,6 @@ sys.path.insert(0, '../client')
from entropy.exceptions import SystemDatabaseError, OnlineMirrorError, \
RepositoryError, PermissionDenied, FileNotFound, SPMError
try:
from entropy.services.exceptions import ServiceConnectionError
except ImportError:
# backward compatibility
ServiceConnectionError = None
try:
from entropy.transceivers.exceptions import TransceiverError, \
TransceiverConnectionError
@@ -872,7 +867,7 @@ def handle_exception(exc_class, exc_instance, exc_tb):
generic_exc_classes = (OnlineMirrorError, RepositoryError,
TransceiverError, PermissionDenied, TransceiverConnectionError,
ServiceConnectionError, FileNotFound, SPMError, SystemError)
FileNotFound, SPMError, SystemError)
if exc_class in generic_exc_classes:
print_error("%s %s. %s." % (
darkred(" * "), exc_instance, _("Cannot continue"),))
-1
View File
@@ -18,7 +18,6 @@ import os
import sys
import time
from entropy.services.exceptions import TimeoutError
from entropy.const import etpConst, etpUi, const_debug_write
from entropy.output import red, darkred, blue, brown, bold, darkgreen, green, \
print_info, print_warning, print_error, purple, teal
@@ -26,7 +26,6 @@ from entropy.cache import EntropyCacher
from entropy.db import EntropyRepository
from entropy.exceptions import RepositoryError, SystemDatabaseError, \
PermissionDenied
from entropy.services.exceptions import EntropyServicesError
from entropy.security import Repository as RepositorySecurity
from entropy.misc import TimeScheduled
from entropy.i18n import _
@@ -1,795 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Client Services UGC Base Commands}.
"""
import os
from entropy.services.exceptions import TransmissionError, \
EntropyServicesError, ServiceConnectionError
from entropy.const import etpConst, const_get_stringtype, const_debug_write, \
const_convert_to_rawstring
from entropy.output import darkblue, bold, blue, darkgreen, darkred, brown
from entropy.i18n import _
from entropy.core.settings.base import SystemSettings
import entropy.tools
import entropy.dump
class Base:
def __init__(self, OutputInterface, Service):
if not hasattr(OutputInterface, 'output'):
raise AttributeError(
"OutputInterface does not have an output method")
elif not hasattr(OutputInterface.output, '__call__'):
raise AttributeError(
"OutputInterface does not have an output method")
from entropy.services.ugc.interfaces import Client as Cl
if not isinstance(Service, Cl):
raise AttributeError(
"entropy.services.ugc.interfaces.Client needed")
import socket, zlib, struct
self.socket, self.zlib, self.struct = socket, zlib, struct
self.Output = OutputInterface
self.Service = Service
self.output_header = ''
self._settings = SystemSettings()
self.standard_answers_map = {
'all_fine': 0,
'not_supported_remotely': 1,
'service_temp_not_avail': 2,
'command_failed': 3,
'wrong_answer': 4,
}
def handle_standard_answer(self, data, repository = None, arch = None,
product = None):
do_skip = False
answer_id = self.standard_answers_map['all_fine']
# elaborate answer
if data is None:
mytxt = _("feature not supported remotely")
self.Output.output(
"[%s:%s|%s:%s|%s:%s] %s" % (
darkblue(_("repo")),
bold(str(repository)),
darkred(_("arch")),
bold(str(arch)),
darkgreen(_("product")),
bold(str(product)),
blue(mytxt),
),
importance = 1,
level = "error",
header = self.output_header
)
do_skip = True
answer_id = self.standard_answers_map['not_supported_remotely']
elif not data:
mytxt = _("service temporarily not available")
self.Output.output(
"[%s:%s|%s:%s|%s:%s] %s" % (
darkblue(_("repo")),
bold(str(repository)),
darkred(_("arch")),
bold(str(arch)),
darkgreen(_("product")),
bold(str(product)),
blue(mytxt),
),
importance = 1,
level = "error",
header = self.output_header
)
do_skip = True
answer_id = self.standard_answers_map['service_temp_not_avail']
elif data == self.Service.answers['no']:
# command failed
mytxt = _("command failed")
self.Output.output(
"[%s:%s|%s:%s|%s:%s] %s" % (
darkblue(_("repo")),
bold(str(repository)),
darkred(_("arch")),
bold(str(arch)),
darkgreen(_("product")),
bold(str(product)),
blue(mytxt),
),
importance = 1,
level = "error",
header = self.output_header
)
do_skip = True
answer_id = self.standard_answers_map['command_failed']
elif data != self.Service.answers['ok']:
mytxt = _("received wrong answer")
# do not spam terminal
if isinstance(data, const_get_stringtype()):
if len(data) > 10:
data = data[:10] + "[...]"
self.Output.output(
"[%s:%s|%s:%s|%s:%s] %s: %s" % (
darkblue(_("repo")),
bold(str(repository)),
darkred(_("arch")),
bold(str(arch)),
darkgreen(_("product")),
bold(str(product)),
blue(mytxt),
repr(data),
),
importance = 1,
level = "error",
header = self.output_header
)
do_skip = True
answer_id = self.standard_answers_map['wrong_answer']
return do_skip, answer_id
def get_result(self, session):
# get the information
cmd = "%s rc" % (session,)
try:
self.Service.transmit(cmd)
except TransmissionError:
entropy.tools.print_traceback()
return None
try:
data = self.Service.receive()
return data
except Exception:
entropy.tools.print_traceback()
return None
def convert_stream_to_object(self, data, gzipped, repository = None,
arch = None, product = None):
# unstream object
error = False
try:
data = self.Service.stream_to_object(data, gzipped)
except (EOFError, IOError, self.zlib.error, entropy.dump.pickle.UnpicklingError,):
const_debug_write(__name__, entropy.tools.get_traceback())
mytxt = _("cannot convert stream into object")
self.Output.output(
"[%s:%s|%s:%s|%s:%s] %s" % (
darkblue(_("repo")),
bold(str(repository)),
darkred(_("arch")),
bold(str(arch)),
darkgreen(_("product")),
bold(str(product)),
blue(mytxt),
),
importance = 1,
level = "error",
header = self.output_header
)
data = None
error = True
return data, error
def retrieve_command_answer(self, cmd, session_id, repository = None,
arch = None, product = None, compression = False):
tries = 3
lasterr = None
while True:
if tries <= 0:
return lasterr
tries -= 1
try:
# send command
self.Service.transmit(cmd)
except TransmissionError:
return None
# receive answer
data = self.Service.receive()
skip, answer_id = self.handle_standard_answer(data, repository,
arch, product)
if skip:
if tries <= 0:
const_debug_write(__name__,
darkred("skipping command, NOT reconnecting"))
else:
const_debug_write(__name__,
darkred("skipping command, reconnect+retry!"))
const_debug_write(__name__, str(answer_id))
# reconnect host and retry
self.Service.reconnect_socket()
continue
data = self.get_result(session_id)
if data is None:
lasterr = None
continue
elif not data:
lasterr = False
continue
objdata, error = self.convert_stream_to_object(data, compression,
repository, arch, product)
if not error:
return objdata
def do_generic_handler(self, cmd, session_id, tries = 10, compression = False):
try:
self.Service.check_socket_connection()
except ServiceConnectionError:
return False, 'connection error'
while True:
try:
result = self.retrieve_command_answer(cmd, session_id,
compression = compression)
if result is None:
return False, 'command not supported' # untranslated on purpose
return result
except (self.socket.error, self.struct.error,) as err:
try:
self.Service.reconnect_socket()
except self.socket.error as exc:
return False, 'connection error %s' % (exc,)
tries -= 1
if tries < 1:
return False, 'connection error %s' % (err,)
def _set_gzip_compression(self, session, do):
self.Service.check_socket_connection()
cmd = "%s %s %s %s zlib" % (
const_convert_to_rawstring(session),
const_convert_to_rawstring('session_config'),
const_convert_to_rawstring('compression'),
const_convert_to_rawstring(do),
)
fail_count = 5
while True:
try:
self.Service.transmit(cmd)
data = self.Service.receive()
except TransmissionError as err:
const_debug_write(__name__,
darkred("_set_gzip_compression: error: " + repr(err)))
fail_count -= 1
if fail_count == 0:
raise
continue
if data == self.Service.answers['ok']:
return True
return False
def service_login(self, username, password, session_id):
cmd = "%s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('login'),
const_convert_to_rawstring(username),
const_convert_to_rawstring(password),
)
return self.do_generic_handler(cmd, session_id)
def service_logout(self, username, session_id):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('logout'),
const_convert_to_rawstring(username),
)
return self.do_generic_handler(cmd, session_id)
def get_logged_user_data(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('user_data'),
)
return self.do_generic_handler(cmd, session_id)
def is_user(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('is_user'),
)
return self.do_generic_handler(cmd, session_id)
def is_developer(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('is_developer'),
)
return self.do_generic_handler(cmd, session_id)
def is_moderator(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('is_moderator'),
)
return self.do_generic_handler(cmd, session_id)
def is_administrator(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('is_administrator'),
)
return self.do_generic_handler(cmd, session_id)
def available_commands(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('available_commands'),
)
return self.do_generic_handler(cmd, session_id)
class Client(Base):
def __init__(self, EntropyInterface, ServiceInterface):
Base.__init__(self, EntropyInterface, ServiceInterface)
def differential_packages_comparison(self, session_id, idpackages,
repository, arch, product):
myidlist = const_convert_to_rawstring(
' '.join([str(x) for x in idpackages]))
cmd = "%s %s %s %s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('repository_server:dbdiff'),
const_convert_to_rawstring(repository),
const_convert_to_rawstring(arch),
const_convert_to_rawstring(product),
const_convert_to_rawstring(
self._settings['repositories']['branch']),
myidlist,
)
# enable zlib compression
try:
compression = self._set_gzip_compression(session_id, True)
except EntropyServicesError:
return False, 'connection error'
data = self.do_generic_handler(cmd, session_id, tries = 5,
compression = compression)
# disable compression
try:
compression = self._set_gzip_compression(session_id, False)
except EntropyServicesError:
return False, 'connection error'
return data
def get_repository_treeupdates(self, session_id, repository, arch, product):
cmd = "%s %s %s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('repository_server:treeupdates'),
const_convert_to_rawstring(repository),
const_convert_to_rawstring(arch),
const_convert_to_rawstring(product),
const_convert_to_rawstring(
self._settings['repositories']['branch']),
)
return self.do_generic_handler(cmd, session_id, tries = 5)
def get_package_sets(self, session_id, repository, arch, product):
cmd = "%s %s %s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('repository_server:get_package_sets'),
const_convert_to_rawstring(repository),
const_convert_to_rawstring(arch),
const_convert_to_rawstring(product),
const_convert_to_rawstring(
self._settings['repositories']['branch']),
)
return self.do_generic_handler(cmd, session_id, tries = 5)
def get_repository_metadata(self, session_id, repository, arch, product):
cmd = "%s %s %s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring(
'repository_server:get_repository_metadata'),
const_convert_to_rawstring(repository),
const_convert_to_rawstring(arch),
const_convert_to_rawstring(product),
const_convert_to_rawstring(
self._settings['repositories']['branch']),
)
return self.do_generic_handler(cmd, session_id, tries = 5)
def get_strict_package_information(self, session_id, idpackages,
repository, arch, product):
cmd = "%s %s %s %s %s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('repository_server:pkginfo_strict'),
True,
const_convert_to_rawstring(repository),
const_convert_to_rawstring(arch),
const_convert_to_rawstring(product),
const_convert_to_rawstring(
self._settings['repositories']['branch']),
const_convert_to_rawstring(' '.join([str(x) for x in idpackages])),
)
# enable zlib compression
try:
compression = self._set_gzip_compression(session_id, True)
except EntropyServicesError:
return False, 'connection error'
data = self.do_generic_handler(cmd, session_id, compression = compression)
# disable compression
try:
compression = self._set_gzip_compression(session_id, False)
except EntropyServicesError:
return False, 'connection error'
return data
def ugc_do_download_stats(self, session_id, package_names):
sub_lists = entropy.tools.split_indexable_into_chunks(
package_names, 100)
last_srv_rc_data = None
for pkgkeys in sub_lists:
release_string = '--N/A--'
rel_file = etpConst['systemreleasefile']
if os.path.isfile(rel_file) and os.access(rel_file, os.R_OK):
with open(rel_file, "r") as f:
release_string = f.read(512)
hw_hash = self._settings['hw_hash']
if not hw_hash:
hw_hash = ''
mydict = {
'branch': self._settings['repositories']['branch'],
'release_string': release_string,
'hw_hash': hw_hash,
'pkgkeys': ' '.join(pkgkeys),
}
xml_string = entropy.tools.xml_from_dict(mydict)
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:do_download_stats'),
const_convert_to_rawstring(xml_string),
)
last_srv_rc_data = self.do_generic_handler(cmd, session_id)
if not isinstance(last_srv_rc_data, tuple):
return last_srv_rc_data
elif last_srv_rc_data[0] != True:
return last_srv_rc_data
return last_srv_rc_data
def ugc_get_downloads(self, session_id, pkgkey):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_downloads'),
pkgkey,
)
return self.do_generic_handler(cmd, session_id)
def ugc_get_alldownloads(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_alldownloads'),
)
# enable zlib compression
try:
compression = self._set_gzip_compression(session_id, True)
except EntropyServicesError:
return False, 'connection error'
rc = self.do_generic_handler(cmd, session_id, compression = compression)
# disable compression
try:
compression = self._set_gzip_compression(session_id, False)
except EntropyServicesError:
return False, 'connection error'
return rc
def ugc_do_vote(self, session_id, pkgkey, vote):
cmd = "%s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:do_vote'),
const_convert_to_rawstring(pkgkey),
const_convert_to_rawstring(vote),
)
return self.do_generic_handler(cmd, session_id)
def ugc_get_vote(self, session_id, pkgkey):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_vote'),
const_convert_to_rawstring(pkgkey),
)
return self.do_generic_handler(cmd, session_id)
def ugc_get_allvotes(self, session_id):
cmd = "%s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_allvotes'),
)
# enable zlib compression
try:
compression = self._set_gzip_compression(session_id, True)
except EntropyServicesError:
return False, 'connection error'
rc = self.do_generic_handler(cmd, session_id, compression = compression)
# disable compression
try:
compression = self._set_gzip_compression(session_id, False)
except EntropyServicesError:
return False, 'connection error'
return rc
def ugc_add_comment(self, session_id, pkgkey, comment, title, keywords):
mydict = {
'comment': comment,
'title': title,
'keywords': keywords,
}
xml_string = entropy.tools.xml_from_dict(mydict)
cmd = "%s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:add_comment'),
const_convert_to_rawstring(pkgkey),
const_convert_to_rawstring(xml_string),
)
return self.do_generic_handler(cmd, session_id)
def ugc_edit_comment(self, session_id, iddoc, new_comment, new_title, new_keywords):
mydict = {
'comment': new_comment,
'title': new_title,
'keywords': new_keywords,
}
xml_string = entropy.tools.xml_from_dict(mydict)
cmd = "%s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:edit_comment'),
const_convert_to_rawstring(iddoc),
const_convert_to_rawstring(xml_string),
)
return self.do_generic_handler(cmd, session_id)
def ugc_remove_comment(self, session_id, iddoc):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:remove_comment'),
const_convert_to_rawstring(iddoc),
)
return self.do_generic_handler(cmd, session_id)
def ugc_remove_image(self, session_id, iddoc):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:remove_image'),
const_convert_to_rawstring(iddoc),
)
return self.do_generic_handler(cmd, session_id)
def ugc_remove_file(self, session_id, iddoc):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:remove_file'),
const_convert_to_rawstring(iddoc),
)
return self.do_generic_handler(cmd, session_id)
def ugc_remove_youtube_video(self, session_id, iddoc):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:remove_youtube_video'),
const_convert_to_rawstring(iddoc),
)
return self.do_generic_handler(cmd, session_id)
def ugc_get_docs(self, session_id, pkgkey):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_alldocs'),
const_convert_to_rawstring(pkgkey),
)
return self.do_generic_handler(cmd, session_id)
def ugc_get_textdocs(self, session_id, pkgkey):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_textdocs'),
const_convert_to_rawstring(pkgkey),
)
return self.do_generic_handler(cmd, session_id)
def ugc_get_textdocs_by_identifiers(self, session_id, identifiers):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_textdocs_by_identifiers'),
const_convert_to_rawstring(' '.join([str(x) for x in identifiers])),
)
return self.do_generic_handler(cmd, session_id)
def ugc_get_documents_by_identifiers(self, session_id, identifiers):
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:get_documents_by_identifiers'),
const_convert_to_rawstring(' '.join([str(x) for x in identifiers])),
)
return self.do_generic_handler(cmd, session_id)
def ugc_send_file_stream(self, session_id, file_path):
if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)):
return False, False, 'cannot read file_path'
import zlib
# enable stream
cmd = "%s %s %s on" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('session_config'),
const_convert_to_rawstring('stream'),
)
status, msg = self.do_generic_handler(cmd, session_id)
if not status:
return False, status, msg
# enable zlib compression
try:
compression = self._set_gzip_compression(session_id, True)
except EntropyServicesError:
return False, 'connection error'
# start streamer
stream_status = True
stream_msg = 'ok'
f = open(file_path, "rb")
chunk = f.read(8192)
base_path = os.path.basename(file_path)
transferred = len(chunk)
max_size = entropy.tools.get_file_size(file_path)
while chunk:
if (not self.Service.quiet) or self.Service.show_progress:
self.Output.output(
"%s, %s: %s" % (
blue(_("User Generated Content")),
darkgreen(_("sending file")),
darkred(base_path),
),
importance = 1,
level = "info",
header = brown(" @@ "),
back = True,
count = (transferred, max_size,),
percent = True
)
chunk = zlib.compress(chunk, 7) # compression level 1-9
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
'stream',
chunk,
)
status, msg = self.do_generic_handler(cmd, session_id, compression = compression)
if not status:
stream_status = status
stream_msg = msg
break
chunk = f.read(8192)
transferred += len(chunk)
f.close()
# disable compression
try:
compression = self._set_gzip_compression(session_id, False)
except EntropyServicesError:
return False, 'connection error'
# disable config
cmd = "%s %s %s off" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('session_config'),
const_convert_to_rawstring('stream'),
)
status, msg = self.do_generic_handler(cmd, session_id)
if not status:
return False, status, msg
return True, stream_status, stream_msg
def ugc_send_file(self, session_id, pkgkey, file_path, doc_type, title,
description, keywords):
status, rem_status, err_msg = self.ugc_send_file_stream(session_id, file_path)
if not (status and rem_status):
return False, err_msg
mydict = {
'doc_type': str(doc_type),
'title': title,
'description': description,
'keywords': keywords,
'file_name': os.path.join(pkgkey, os.path.basename(file_path)),
'real_filename': os.path.basename(file_path),
}
xml_string = entropy.tools.xml_from_dict(mydict)
cmd = "%s %s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:register_stream'),
pkgkey,
xml_string,
)
return self.do_generic_handler(cmd, session_id)
def report_error(self, session_id, error_data):
import zlib
xml_string = entropy.tools.xml_from_dict_extended(error_data)
xml_comp_string = zlib.compress(xml_string)
cmd = "%s %s %s" % (
const_convert_to_rawstring(session_id),
const_convert_to_rawstring('ugc:report_error'),
const_convert_to_rawstring(xml_comp_string),
)
return self.do_generic_handler(cmd, session_id)
@@ -1,916 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Client Services UGC Base Interfaces}.
"""
import os
import shutil
from entropy.core import Singleton
from entropy.core.settings.base import SystemSettings
from entropy.exceptions import RepositoryError, PermissionDenied
from entropy.services.exceptions import ServiceConnectionError, \
EntropyServicesError
from entropy.cache import MtimePingus, EntropyCacher
from entropy.const import etpConst, const_setup_file, const_setup_perms
from entropy.i18n import _
import entropy.dump
class Client:
ssl_connection = True
def __init__(self, entropy_client, quiet = True, show_progress = False):
from entropy.client.interfaces import Client as Cl
if not isinstance(entropy_client, Cl):
mytxt = "A valid Client based instance is needed"
raise AttributeError(mytxt)
import socket, threading
self.socket, self.threading = socket, threading
import struct
self.struct = struct
self.Entropy = entropy_client
self.store = AuthStore()
self.quiet = quiet
self.show_progress = show_progress
self.UGCCache = Cache(self)
self.TxLocks = {}
self._cacher = EntropyCacher()
def connect_to_service(self, repository, timeout = None):
sys_settings = SystemSettings()
avail_data = sys_settings['repositories']['available']
# also try excluded repos
if repository not in avail_data:
avail_data = sys_settings['repositories']['excluded']
if repository not in avail_data:
raise RepositoryError('repository is not available')
# unsupported by repository?
if 'service_uri' not in avail_data[repository]:
return None
if 'service_port' not in avail_data[repository]:
return None
url = avail_data[repository]['service_uri']
port = avail_data[repository]['service_port']
if self.ssl_connection:
port = avail_data[repository]['ssl_service_port']
from entropy.services.ugc.interfaces import Client
from entropy.client.services.ugc.commands import Client as CommandsClient
args = [self.Entropy, CommandsClient]
kwargs = {
'ssl': self.ssl_connection,
'quiet': self.quiet,
'show_progress': self.show_progress
}
if timeout is not None:
kwargs['socket_timeout'] = timeout
srv = Client(*args, **kwargs)
srv.connect(url, port)
return srv
def get_service_connection(self, repository, check = True, timeout = None):
if check:
if not self.is_repository_eapi3_aware(repository):
return None
try:
srv = self.connect_to_service(repository, timeout = timeout)
except (RepositoryError, ServiceConnectionError,):
return None
return srv
def is_repository_eapi3_aware(self, repository, _use_cache = True):
aware = self.UGCCache._get_live_cache_item(repository,
'is_repository_eapi3_aware')
if aware is not None:
return aware
def _get_awareness():
try:
srv = self.get_service_connection(repository, check = False,
timeout = 6)
if srv is None:
rc = False
else:
session = srv.open_session()
if session is not None:
srv.close_session(session)
srv.disconnect()
rc = True
else:
rc = False
except EntropyServicesError:
rc = False
return rc
# Life is hard, and socket communication can be very annoying
# over a non-performant connection. So, the only way to circumvent this
# is to cache results somewhere.
cache_id = "entropy.client.interfaces.ugc.is_repository_eapi3_aware_" \
+ repository
pingus = MtimePingus()
passed = True
if _use_cache:
# are 3 days passed?
passed = pingus.hours_passed(cache_id, 24*3)
if passed:
aware = _get_awareness()
# update pingus mtime
pingus.ping(cache_id)
else:
# then load data from disk cache
cached = self._cacher.pop(cache_id)
if cached is None:
# no cache on disk
aware = _get_awareness()
self._cacher.push(cache_id, aware, async = False)
pingus.ping(cache_id)
else:
aware = cached
self.UGCCache._set_live_cache_item(repository,
'is_repository_eapi3_aware', aware)
return aware
def read_login(self, repository):
return self.store.read_login(repository)
def remove_login(self, repository):
return self.store.remove_login(repository)
def do_login(self, repository, force = False):
login_data = self.read_login(repository)
if (login_data is not None) and not force:
return True, _('ok')
aware = self.is_repository_eapi3_aware(repository)
if not aware:
return False, _('repository does not support EAPI3')
def fake_callback(*args, **kwargs):
return True
attempts = 3
while attempts:
# use input box to read login
input_params = [
('username', _('Username'), fake_callback, False),
('password', _('Password'), fake_callback, True)
]
login_data = self.Entropy.input_box(
"%s %s %s" % (
_('Please login against'), repository, _('repository'),),
input_params,
cancel_button = True
)
if not login_data:
return False, _('login abort')
# now verify
srv = self.get_service_connection(repository)
if srv is None:
return False, _('connection issues')
session = srv.open_session()
if session is None:
return False, _('cannot open a session')
login_status, login_msg = srv.CmdInterface.service_login(
login_data['username'], login_data['password'], session)
if not login_status:
srv.close_session(session)
srv.disconnect()
self.Entropy.ask_question("%s: %s" % (
_("Access denied. Login failed"), login_msg,),
responses = [_("Ok")])
attempts -= 1
continue
# login accepted, store it?
srv.close_session(session)
srv.disconnect()
rc = self.Entropy.ask_question(
_("Login successful. Do you want to save these credentials ?"))
save = False
if rc == _("Yes"):
save = True
self.store.store_login(login_data['username'],
login_data['password'], repository, save = save)
return True, _('ok')
def login(self, repository, force = False):
if repository not in self.TxLocks:
self.TxLocks[repository] = self.threading.Lock()
with self.TxLocks[repository]:
return self.do_login(repository, force = force)
def logout(self, repository):
return self.store.remove_login(repository)
def do_cmd(self, repository, login_required, func, args, kwargs):
if repository not in self.TxLocks:
self.TxLocks[repository] = self.threading.Lock()
with self.TxLocks[repository]:
if login_required:
status, err_msg = self.do_login(repository)
if not status:
return False, err_msg
srv = self.get_service_connection(repository)
if srv is None:
return False, 'no connection'
session = srv.open_session()
if session is None:
return False, 'no session'
args.insert(0, session)
if login_required:
stored_pass = False
while True:
# login
login_data = self.read_login(repository)
if login_data is None:
status, msg = self.login(repository)
if not status:
return status, msg
username, password = self.read_login(repository)
else:
stored_pass = True
username, password = login_data
logged, error = srv.CmdInterface.service_login(username,
password, session)
if not logged:
if stored_pass:
stored_pass = False
self.remove_login(repository)
continue
srv.close_session(session)
srv.disconnect()
return logged, error
break
try:
cmd_func = getattr(srv.CmdInterface, func)
except AttributeError:
return False, 'local function not available'
rslt = cmd_func(*args, **kwargs)
try:
srv.close_session(session)
srv.disconnect()
except ServiceConnectionError:
return False, 'no connection'
return rslt
def get_comments(self, repository, pkgkey):
return self.do_cmd(repository, False, "ugc_get_textdocs", [pkgkey], {})
def get_comments_by_identifiers(self, repository, identifiers):
return self.do_cmd(repository, False,
"ugc_get_textdocs_by_identifiers", [identifiers], {})
def get_documents_by_identifiers(self, repository, identifiers):
return self.do_cmd(repository, False,
"ugc_get_documents_by_identifiers", [identifiers], {})
def add_comment(self, repository, pkgkey, comment, title, keywords):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_add_comment",
[pkgkey, comment, title, keywords], {})
def edit_comment(self, repository, iddoc, new_comment, new_title, new_keywords):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_edit_comment",
[iddoc, new_comment, new_title, new_keywords], {})
def remove_comment(self, repository, iddoc):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_remove_comment", [iddoc], {})
def add_vote(self, repository, pkgkey, vote):
data = self.do_cmd(repository, True, "ugc_do_vote", [pkgkey, vote], {})
if isinstance(data, tuple):
voted, add_err_msg = data
else:
return False, 'wrong server answer'
if voted:
self.get_vote(repository, pkgkey)
return voted, add_err_msg
def get_vote(self, repository, pkgkey):
vote, err_msg = self.do_cmd(repository, False, "ugc_get_vote", [pkgkey], {})
if isinstance(vote, float):
mydict = {pkgkey: vote}
self.UGCCache.update_vote_cache(repository, mydict)
return vote, err_msg
def get_all_votes(self, repository):
votes_dict, err_msg = self.do_cmd(repository, False, "ugc_get_allvotes", [], {})
if isinstance(votes_dict, dict):
self.UGCCache.update_vote_cache(repository, votes_dict)
return votes_dict, err_msg
def get_downloads(self, repository, pkgkey):
data = self.do_cmd(repository, False, "ugc_get_downloads", [pkgkey], {})
if isinstance(data, tuple):
downloads, err_msg = data
else:
return False, 'wrong server answer'
if downloads:
mydict = {pkgkey: downloads}
self.UGCCache.update_downloads_cache(repository, mydict)
return downloads, err_msg
def get_all_downloads(self, repository):
down_dict, err_msg = self.do_cmd(repository, False, "ugc_get_alldownloads", [], {})
if isinstance(down_dict, dict):
self.UGCCache.update_downloads_cache(repository, down_dict)
return down_dict, err_msg
def add_download_stats(self, repository, pkgkeys):
return self.do_cmd(repository, False, "ugc_do_download_stats", [pkgkeys], {})
def send_file(self, repository, pkgkey, file_path, title, description, keywords):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_send_file",
[pkgkey, file_path, etpConst['ugc_doctypes']['generic_file'], title, description, keywords], {})
def remove_file(self, repository, iddoc):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_remove_file", [iddoc], {})
def send_image(self, repository, pkgkey, image_path, title, description, keywords):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_send_file",
[pkgkey, image_path, etpConst['ugc_doctypes']['image'], title, description, keywords], {})
def remove_image(self, repository, iddoc):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_remove_image", [iddoc], {})
def send_youtube_video(self, repository, pkgkey, video_path, title, description, keywords):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_send_file",
[pkgkey, video_path, etpConst['ugc_doctypes']['youtube_video'], title, description, keywords], {})
def remove_youtube_video(self, repository, iddoc):
self.UGCCache.clear_alldocs_cache(repository)
return self.do_cmd(repository, True, "ugc_remove_youtube_video", [iddoc], {})
def get_docs(self, repository, pkgkey):
data = self.do_cmd(repository, False, "ugc_get_docs", [pkgkey], {})
if isinstance(data, tuple):
docs_data, err_msg = data
else:
return False, 'wrong server answer'
self.UGCCache.save_alldocs_cache(pkgkey, repository, docs_data)
return docs_data, err_msg
def get_icon(self, repository, pkgkey):
docs_data, err_msg = self.get_docs(repository, pkgkey)
if not docs_data:
return None
elif not isinstance(docs_data, (tuple, list)):
return None
return self.UGCCache.get_icon_cache(pkgkey, repository)
def send_document_autosense(self, repository, pkgkey, ugc_type, data,
title, description, keywords):
if ugc_type == etpConst['ugc_doctypes']['generic_file']:
return self.send_file(repository, pkgkey, data, title,
description, keywords)
elif ugc_type == etpConst['ugc_doctypes']['image']:
return self.send_image(repository, pkgkey, data, title,
description, keywords)
elif ugc_type == etpConst['ugc_doctypes']['youtube_video']:
return self.send_youtube_video(repository, pkgkey, data, title,
description, keywords)
elif ugc_type == etpConst['ugc_doctypes']['comments']:
return self.add_comment(repository, pkgkey,
description, title, keywords)
return None, 'type not supported locally'
def remove_document_autosense(self, repository, iddoc, ugc_type):
if ugc_type == etpConst['ugc_doctypes']['generic_file']:
return self.remove_file(repository, iddoc)
elif ugc_type == etpConst['ugc_doctypes']['image']:
return self.remove_image(repository, iddoc)
elif ugc_type == etpConst['ugc_doctypes']['youtube_video']:
return self.remove_youtube_video(repository, iddoc)
elif ugc_type == etpConst['ugc_doctypes']['comments']:
return self.remove_comment(repository, iddoc)
return None, 'type not supported locally'
def report_error(self, repository, error_data):
return self.do_cmd(repository, False, "report_error", [error_data], {})
class AuthStore(Singleton):
access_file = etpConst['ugc_accessfile']
def init_singleton(self):
from xml.dom import minidom
from xml.parsers import expat
self.expat = expat
self.minidom = minidom
self.setup_store_paths()
try:
self.setup_permissions()
except IOError:
pass
self.store = {}
try:
self.xmldoc = self.minidom.parse(self.access_file)
except (self.expat.ExpatError, IOError, ValueError,):
# ValueError: bad marshal data, wtf!?
self.xmldoc = None
if self.xmldoc is not None:
try:
self.parse_document()
except self.expat.ExpatError:
self.xmldoc = None
self.store = {}
def setup_store_paths(self):
myhome = os.getenv("HOME")
if myhome is not None:
if os.path.isdir(myhome) and os.access(myhome, os.W_OK):
self.access_file = os.path.join(myhome, ".config/entropy",
os.path.basename(self.access_file))
self.access_dir = os.path.dirname(self.access_file)
def setup_permissions(self):
if not os.path.isdir(self.access_dir):
os.makedirs(self.access_dir)
if not os.path.isfile(self.access_file):
f = open(self.access_file, "w")
f.close()
gid = etpConst['entropygid']
if gid is None:
gid = 0
try:
const_setup_file(self.access_dir, gid, 0o700)
except OSError:
pass
try:
const_setup_file(self.access_file, gid, 0o600)
except OSError:
pass
def parse_document(self):
self.store.clear()
store = self.xmldoc.getElementsByTagName("store")[0]
repositories = store.getElementsByTagName("repository")
for repository in repositories:
repoid = repository.getAttribute("id")
if not repoid:
continue
username = repository.getElementsByTagName("username")[0].firstChild.data.strip()
password = repository.getElementsByTagName("password")[0].firstChild.data.strip()
self.store[repoid] = {'username': username, 'password': password}
def store_login(self, username, password, repository, save = True):
self.store[repository] = {'username': username, 'password': password}
if save:
self.save_store()
def save_store(self):
self.xmldoc = self.minidom.Document()
store = self.xmldoc.createElement("store")
for repository in self.store:
repo = self.xmldoc.createElement("repository")
repo.setAttribute('id', repository)
# username
username = self.xmldoc.createElement("username")
username_value = self.xmldoc.createTextNode(
self.store[repository]['username'])
username.appendChild(username_value)
repo.appendChild(username)
# password
password = self.xmldoc.createElement("password")
password_value = self.xmldoc.createTextNode(
self.store[repository]['password'])
password.appendChild(password_value)
repo.appendChild(password)
store.appendChild(repo)
self.xmldoc.appendChild(store)
f = None
try:
f = open(self.access_file, "w")
f.writelines(self.xmldoc.toprettyxml(indent=" "))
f.flush()
self.setup_permissions()
except IOError:
# no permissions?
pass
finally:
if f is not None:
try:
f.close()
except IOError:
pass
self.parse_document()
def remove_login(self, repository, save = True):
if repository in self.store:
del self.store[repository]
if save:
self.save_store()
def read_login(self, repository):
data = self.store.get(repository)
if data is None:
return None
return data['username'], data['password']
class Cache:
CACHE_KEYS = {
'ugc_votes': 'ugc_votes',
'ugc_downloads': 'ugc_downloads',
'ugc_docs': 'ugc_docs',
}
CACHE_DIR = os.path.join(etpConst['entropyworkdir'], "ugc_cache")
PKG_ICON_IDENTIFIER = "__icon__"
def __init__(self, UGCClientInstance):
if not isinstance(UGCClientInstance, Client):
raise AttributeError(
"entropy.client.services.ugc.Client instance required")
import threading
self.CacheLock = threading.Lock()
self.Service = UGCClientInstance
self.xcache = {}
def _get_live_cache_item(self, repository, item):
if repository not in self.xcache:
return None
return self.xcache[repository].get(item)
def _is_live_cache_item_available(self, repository, item):
if repository not in self.xcache:
return False
return item in self.xcache[repository]
def _set_live_cache_item(self, repository, item, obj):
if repository not in self.xcache:
self.xcache[repository] = {}
if type(obj) in (list, tuple,):
my_obj = obj[:]
elif type(obj) in (set, frozenset, dict,):
my_obj = obj.copy()
else:
my_obj = obj
self.xcache[repository][item] = my_obj
def _clear_live_cache_item(self, repository, item):
if repository not in self.xcache:
return
if item not in self.xcache[repository]:
return
del self.xcache[repository][item]
def _get_store_cache_file(self, iddoc, repository, doc_url,
setup_dir = False):
base_dir = os.path.join(Cache.CACHE_DIR,
Cache.CACHE_KEYS['ugc_docs'], repository, str(iddoc))
cache_path = os.path.join(base_dir, "_"+doc_url)
cache_dir = os.path.dirname(cache_path)
if setup_dir and (not os.path.isdir(cache_dir)):
try:
os.makedirs(cache_dir, 0o775)
const_setup_perms(cache_dir, etpConst['entropygid'])
except (OSError, IOError,):
return cache_path
return cache_path
def _get_vote_cache_file(self, repository):
return os.path.join(Cache.CACHE_DIR,
self._get_vote_cache_dir(repository))
def _get_downloads_cache_file(self, repository):
return os.path.join(Cache.CACHE_DIR,
self._get_downloads_cache_dir(repository))
def _get_alldocs_cache_file(self, pkgkey, repository):
return os.path.join(Cache.CACHE_DIR,
self._get_alldocs_cache_dir(repository)+"/"+pkgkey)
def _get_alldocs_cache_dir(self, repository):
return Cache.CACHE_KEYS['ugc_docs']+"/"+repository
def _get_downloads_cache_dir(self, repository):
return Cache.CACHE_KEYS['ugc_downloads']+"/"+repository
def _get_vote_cache_dir(self, repository):
return Cache.CACHE_KEYS['ugc_votes']+"/"+repository
def _get_vote_cache_key(self, repository):
return 'get_vote_cache_'+repository
def _get_downloads_cache_key(self, repository):
return 'get_downloads_cache_'+repository
def _get_alldocs_cache_key(self, repository):
return 'get_package_alldocs_cache_'+repository
def _clear_cache_dir(self, cache_dir):
try:
shutil.rmtree(cache_dir, True)
except (shutil.Error, OSError, IOError,):
return
def _complete_cache_path(self, cache_file):
return os.path.join(Cache.CACHE_DIR, cache_file)
def store_document(self, iddoc, repository, doc_url):
cache_file = self._get_store_cache_file(iddoc, repository, doc_url,
setup_dir = True)
cache_dir = os.path.dirname(cache_file)
if not os.access(cache_dir, os.W_OK):
raise PermissionDenied("PermissionDenied: %s %s" % (
_("Cannot write to cache directory"), cache_dir,))
if os.path.isfile(cache_file) or os.path.islink(cache_file):
try:
os.remove(cache_file)
except OSError:
raise PermissionDenied("PermissionDenied: %s %s" % (
_("Cannot remove cache file"), cache_file,))
fetcher = self.Service.Entropy._url_fetcher(doc_url, cache_file,
resume = False)
rc = fetcher.download()
if rc in ("-1", "-2", "-3", "-4"):
return None
if not os.path.isfile(cache_file):
return None
try:
os.chmod(cache_file, 0o664)
if etpConst['entropygid'] is not None:
os.chown(cache_file, -1, etpConst['entropygid'])
except OSError:
raise PermissionDenied("PermissionDenied: %s %s" % (
_("Cannot write to cache file"), cache_file,))
del fetcher
return cache_file
def get_stored_document(self, iddoc, repository, doc_url):
cache_file = self._get_store_cache_file(iddoc, repository, doc_url)
if os.path.isfile(cache_file) and os.access(cache_file, os.R_OK):
return cache_file
def update_vote_cache(self, repository, vote_dict):
cached = self.get_vote_cache(repository)
if cached is None:
cached = vote_dict.copy()
else:
cached.update(vote_dict)
self.save_vote_cache(repository, cached)
def update_downloads_cache(self, repository, down_dict):
cached = self.get_downloads_cache(repository)
if cached is None:
cached = down_dict.copy()
else:
cached.update(down_dict)
self.save_downloads_cache(repository, cached)
def clear_alldocs_cache(self, repository):
with self.CacheLock:
self._clear_cache_dir(
self._get_alldocs_cache_dir(repository))
self._clear_live_cache_item(repository,
self._get_alldocs_cache_key(repository))
def clear_downloads_cache(self, repository):
with self.CacheLock:
self._clear_cache_dir(
self._get_downloads_cache_dir(repository))
self._clear_live_cache_item(repository,
self._get_downloads_cache_key(repository))
def clear_vote_cache(self, repository):
with self.CacheLock:
self._clear_cache_dir(
self._get_vote_cache_dir(repository))
self._clear_live_cache_item(repository,
self._get_vote_cache_key(repository))
def clear_live_cache(self):
self.xcache.clear()
def clear_cache(self, repository):
self.clear_alldocs_cache(repository)
self.clear_downloads_cache(repository)
self.clear_vote_cache(repository)
self.xcache.clear()
def get_vote_cache(self, repository):
cache_key = self._get_vote_cache_key(repository)
cached = self._get_live_cache_item(repository, cache_key)
if cached is not None:
return cached
with self.CacheLock:
cache_file = self._get_vote_cache_file(repository)
try:
data = entropy.dump.loadobj(
cache_file,
complete_path = True)
if data is not None:
self._set_live_cache_item(repository, cache_key, data)
except (IOError, EOFError, OSError):
data = None
return data
def is_vote_cached(self, repository):
cache_key = self._get_vote_cache_key(repository)
cached = self._is_live_cache_item_available(repository, cache_key)
if cached:
return True
cache_file = self._get_vote_cache_file(repository)
avail = os.path.isfile(cache_file) and os.access(cache_file, os.R_OK)
if not avail:
return False
try:
entropy.dump.loadobj(cache_file, complete_path = True)
except (IOError, EOFError, OSError):
return False
return True
def get_downloads_cache(self, repository):
cache_key = self._get_downloads_cache_key(repository)
cached = self._get_live_cache_item(repository, cache_key)
if cached is not None:
return cached
with self.CacheLock:
cache_file = self._get_downloads_cache_file(repository)
try:
data = entropy.dump.loadobj(cache_file, complete_path = True)
if data is not None:
self._set_live_cache_item(repository, cache_key, data)
except (IOError, EOFError, OSError):
data = None
return data
def is_downloads_cached(self, repository):
cache_key = self._get_downloads_cache_key(repository)
cached = self._is_live_cache_item_available(repository, cache_key)
if cached:
return True
cache_file = self._get_downloads_cache_file(repository)
avail = os.path.isfile(cache_file) and os.access(cache_file, os.R_OK)
if not avail:
return False
try:
entropy.dump.loadobj(cache_file, complete_path = True)
except (IOError, EOFError, OSError):
return False
return True
def get_alldocs_cache(self, pkgkey, repository):
cache_key = self._get_alldocs_cache_key(repository)
cached = self._get_live_cache_item(repository, cache_key)
if isinstance(cached, dict):
if pkgkey in cached:
return cached[pkgkey]
else:
cached = {}
with self.CacheLock:
cache_file = self._get_alldocs_cache_file(pkgkey, repository)
try:
data = entropy.dump.loadobj(cache_file, complete_path = True)
if data is not None:
cached[pkgkey] = data
self._set_live_cache_item(repository, cache_key, cached)
except (IOError, EOFError, OSError):
data = None
return data
def is_alldocs_cached(self, pkgkey, repository):
cache_key = self._get_alldocs_cache_key(repository)
cached = self._is_live_cache_item_available(repository, cache_key)
if cached:
return True
cache_file = self._get_alldocs_cache_file(pkgkey, repository)
avail = os.path.isfile(cache_file) and os.access(cache_file, os.R_OK)
if not avail:
return False
try:
entropy.dump.loadobj(cache_file, complete_path = True)
except (IOError, EOFError, OSError):
return False
return True
def get_icon_cache(self, pkgkey, repository):
docs_cache = self.get_alldocs_cache(pkgkey, repository)
if docs_cache is None:
return None
elif not isinstance(docs_cache, (list, tuple)):
return None
img_doc_type = etpConst['ugc_doctypes']['image']
icon_id = Cache.PKG_ICON_IDENTIFIER
try:
icon_elements = [x for x in docs_cache if \
x['iddoctype'] == img_doc_type and x['title'] == icon_id]
except TypeError:
# cache corruption, invalid data, misc bullshit
return None
if not icon_elements:
return None
# get first (chronologically) icon
icon_elements = sorted(icon_elements, key = lambda x: x['ts'])
return icon_elements[0]
def save_vote_cache(self, repository, vote_dict):
with self.CacheLock:
self._clear_live_cache_item(repository,
self._get_vote_cache_key(repository))
cache_file = self._get_vote_cache_file(repository)
entropy.dump.dumpobj(cache_file, vote_dict, complete_path = True)
def save_downloads_cache(self, repository, down_dict):
with self.CacheLock:
self._clear_live_cache_item(repository,
self._get_downloads_cache_key(repository))
cache_file = self._get_downloads_cache_file(repository)
entropy.dump.dumpobj(cache_file, down_dict, complete_path = True)
def save_alldocs_cache(self, pkgkey, repository, alldocs_dict):
with self.CacheLock:
self._clear_live_cache_item(repository,
self._get_alldocs_cache_key(repository))
cache_file = self._get_alldocs_cache_file(pkgkey, repository)
entropy.dump.dumpobj(cache_file, alldocs_dict, complete_path = True)
def get_package_vote(self, repository, pkgkey):
cache = self.get_vote_cache(repository)
if not cache:
return 0.0
elif not isinstance(cache, dict):
return 0.0
elif pkgkey not in cache:
return 0.0
return cache[pkgkey]
def get_package_downloads(self, repository, pkgkey):
cache = self.get_downloads_cache(repository)
if not cache:
return 0
elif not isinstance(cache, dict):
return 0
elif pkgkey not in cache:
return 0
try:
return int(cache[pkgkey])
except ValueError:
return 0
@@ -1,786 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Authentication Interfaces}.
"""
import os
import time
import random
from entropy.services.skel import Authenticator, RemoteDatabase
from entropy.exceptions import PermissionDenied
from entropy.const import etpConst, const_isstring, const_convert_to_unicode
from entropy.i18n import _
import entropy.tools
class phpBB3Auth(Authenticator, RemoteDatabase):
def __init__(self):
Authenticator.__init__(self)
RemoteDatabase.__init__(self)
self.itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
self.USER_NORMAL = 0
self.USER_INACTIVE = 1
self.USER_IGNORE = 2
self.USER_FOUNDER = 3
self.REGISTERED_USERS_GROUP = 7895
self.ADMIN_GROUPS = [7893, 7898]
self.MODERATOR_GROUPS = [484]
self.DEVELOPER_GROUPS = [7900]
self.USERNAME_LENGTH_RANGE = list(range(3, 21))
self.PASSWORD_LENGTH_RANGE = list(range(6, 31))
self.PRIVMSGS_NO_BOX = -3
self.NOTIFY_EMAIL = 0
self.FAKE_USERNAME = 'already_authed'
self.USER_AGENT = "Entropy/%s (compatible; %s; %s: %s %s %s)" % (
etpConst['entropyversion'],
"Entropy",
"UGC",
os.uname()[0],
os.uname()[4],
os.uname()[2],
)
self.TABLE_PREFIX = 'phpbb_'
self.do_update_session_table = True
def validate_username_regex(self, username):
allow_name_chars = self._get_config_value("allow_name_chars")
if allow_name_chars == "USERNAME_CHARS_ANY":
regex = '.+'
elif allow_name_chars == "USERNAME_ALPHA_ONLY":
regex = '[A-Za-z0-9]+'
elif allow_name_chars == "USERNAME_ALPHA_SPACERS":
regex = '[A-Za-z0-9-[\]_+ ]+'
elif allow_name_chars == "USERNAME_LETTER_NUM":
regex = '[a-zA-Z0-9]+'
elif allow_name_chars == "USERNAME_LETTER_NUM_SPACERS":
regex = '[-\]_+ [a-zA-Z0-9]+'
else: # USERNAME_ASCII
regex = '[\x01-\x7F]+'
regex = "^%s$" % (regex,)
import re
myreg = re.compile(regex)
if myreg.match(username):
del myreg
return True
return False
def does_username_exist(self, username, username_clean):
self.check_connection()
self.cursor.execute('SELECT user_id FROM '+self.TABLE_PREFIX+'users WHERE `username_clean` = %s OR LOWER(`username`) = %s', (username_clean, username.lower(),))
data = self.cursor.fetchone()
if not data:
return False
if not isinstance(data, dict):
return False
if 'user_id' not in data:
return False
return True
def does_email_exist(self, email):
self.check_connection()
self.cursor.execute('SELECT user_id FROM '+self.TABLE_PREFIX+'users WHERE `user_email` = %s', (email,))
data = self.cursor.fetchone()
if not data:
return False
if not isinstance(data, dict):
return False
if 'user_id' not in data:
return False
return True
def is_username_allowed(self, username):
self.check_connection()
self.cursor.execute('SELECT disallow_id FROM '+self.TABLE_PREFIX+'disallow WHERE `disallow_username` = %s', (username,))
data = self.cursor.fetchone()
if not data:
return True
if not isinstance(data, dict):
return True
if 'disallow_id' not in data:
return True
return False
def validate_username_string(self, username, username_clean):
try:
const_convert_to_unicode(username.encode('utf-8'))
except (UnicodeDecodeError, UnicodeEncodeError,):
return False, 'Invalid username'
if ("&quot;" in username) or ("'" in username) or ('"' in username) or \
(" " in username):
return False, 'Invalid username'
try:
valid = self.validate_username_regex(username)
except:
return False, 'Username contains bad characters'
if not valid:
return False, 'Invalid username'
exists = self.does_username_exist(username, username_clean)
if exists:
return False, 'Username already taken'
allowed = self.is_username_allowed(username)
if not allowed:
return False, 'Username not allowed'
return True, 'All fine'
def _generate_email_hash(self, email):
import binascii
return str(binascii.crc32(email.lower())) + str(len(email))
def activate_user(self, user_id):
self.check_connection()
self.cursor.execute('UPDATE '+self.TABLE_PREFIX+'users SET user_type = %s WHERE `user_id` = %s', (self.USER_NORMAL, user_id,))
return True, user_id
def generate_username_clean(self, username):
import re
username_clean = username.lower()
username_clean = re.sub(r'(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)', '', username_clean)
username_clean = re.sub(r' {2,}', ' ', username_clean)
username_clean = username_clean.strip()
return username_clean
def register_user(self, username, password, email, activate = False):
if len(username) not in self.USERNAME_LENGTH_RANGE:
return False, 'Username not in range'
if len(password) not in self.PASSWORD_LENGTH_RANGE:
return False, 'Password not in range'
valid = entropy.tools.is_valid_email(email)
if not valid:
return False, 'Invalid email'
# create the clean one
username_clean = self.generate_username_clean(username)
# check username validity
status, err_msg = self.validate_username_string(username, username_clean)
if not status:
return False, err_msg
# check email
exists = self.does_email_exist(email)
if exists:
return False, 'Email already in use'
# now cross fingers
status, user_id = self.__register(username, username_clean, password, email, activate)
if not status:
return False, 'Invalid username (duplicated)'
return True, user_id
def __register(self, username, username_clean, password, email, activate):
email_hash = self._generate_email_hash(email)
password_hash = self._get_password_hash(password.encode('utf-8'))
time_now = int(time.time())
user_type = self.USER_INACTIVE
if activate:
user_type = self.USER_NORMAL
registration_data = {
'username': username,
'username_clean': username_clean,
'user_password': password_hash,
'user_pass_convert': 0,
'user_email': email.lower(),
'user_email_hash': email_hash,
'group_id': self.REGISTERED_USERS_GROUP,
'user_type': user_type,
'user_permissions': '',
'user_timezone': self._get_config_value('board_timezone'),
'user_dateformat': self._get_config_value('default_dateformat'),
'user_lang': self._get_config_value('default_lang'),
'user_style': self._get_config_value('default_style'),
'user_actkey': '',
'user_ip': '',
'user_regdate': time_now,
'user_passchg': time_now,
'user_options': 895, # ? don't ask me
'user_inactive_reason': 0,
'user_inactive_time': 0,
'user_lastmark': time_now,
'user_lastvisit': 0,
'user_lastpost_time': 0,
'user_lastpage': '',
'user_posts': 0,
'user_dst': self._get_config_value('board_dst'),
'user_colour': '',
'user_occ': '',
'user_interests': '',
'user_avatar': '',
'user_avatar_type': 0,
'user_avatar_width': 0,
'user_avatar_height': 0,
'user_new_privmsg': 0,
'user_unread_privmsg': 0,
'user_last_privmsg': 0,
'user_message_rules': 0,
'user_full_folder': self.PRIVMSGS_NO_BOX,
'user_emailtime': 0,
'user_notify': 0,
'user_notify_pm': 1,
'user_notify_type': self.NOTIFY_EMAIL,
'user_allow_pm': 1,
'user_allow_viewonline': 1,
'user_allow_viewemail': 1,
'user_allow_massemail': 1,
'user_sig': '',
'user_sig_bbcode_uid': '',
'user_sig_bbcode_bitfield': '',
'user_form_salt': self._get_unique_id(),
}
sql = self._generate_sql('insert', self.TABLE_PREFIX+'users', registration_data)
self.cursor.execute(sql)
user_id = self.cursor.lastrowid
# now insert into the default group
group_data = {
'user_id': user_id,
'group_id': self.REGISTERED_USERS_GROUP,
'user_pending': 0,
}
sql = self._generate_sql('insert', self.TABLE_PREFIX+'user_group', group_data)
try:
self.cursor.execute(sql)
except self.mysql_exceptions.IntegrityError as e:
# for sure it's about duplicated entry
return False, 1062
# set some misc config shit
self._set_config_value('newest_user_id', user_id)
self._set_config_value('newest_username', username)
self._set_config_value('num_users', int(self._get_config_value('num_users'))+1)
self.cursor.execute('SELECT group_colour FROM '+self.TABLE_PREFIX+'groups WHERE group_id = %s', (group_data['group_id'],))
data = self.cursor.fetchone()
gcolor = None
if isinstance(data, dict):
if 'group_colour' in data:
gcolor = data['group_colour']
if gcolor:
self._set_config_value('newest_user_colour', gcolor)
return True, user_id
def login(self):
self.check_connection()
self.check_login_data()
if 'username' not in self.login_data:
raise PermissionDenied('PermissionDenied: %s' % (_('no username specified'),))
elif 'password' not in self.login_data:
raise PermissionDenied('PermissionDenied: %s' % (_('no password specified'),))
if not self.login_data['password']:
raise PermissionDenied('PermissionDenied: %s' % (_('empty password'),))
elif not self.login_data['username']:
raise PermissionDenied('PermissionDenied: %s' % (_('empty username'),))
self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'users WHERE username = %s', (self.login_data['username'],))
data = self.cursor.fetchone()
if not data:
raise PermissionDenied('PermissionDenied: %s' % (_('user not found'),))
if data['user_pass_convert']:
raise PermissionDenied('PermissionDenied: %s' % (
_('you need to login on the website to update your password format'),
)
)
valid = self._phpbb3_check_hash(self.login_data['password'], data['user_password'])
if not valid:
raise PermissionDenied('PermissionDenied: %s' % (_('wrong password'),))
user_type = data['user_type']
if (user_type == self.USER_INACTIVE) or (user_type == self.USER_IGNORE):
raise PermissionDenied('PermissionDenied: %s' % (_('user inactive'),))
banned = self.is_user_banned(data['user_id'])
if banned:
raise PermissionDenied('PermissionDenied: %s' % (_('user banned'),))
self.login_data.update(data)
self.logged_in = True
return self.logged_in
def disconnect(self):
if self.is_logged_in():
self.logout()
RemoteDatabase.disconnect(self)
def logout(self):
self.check_connection()
self.check_login_data()
self.logged_in = False
self.login_data.clear()
return True
def get_user_data(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
return self.cursor.fetchone()
def get_user_birthday(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT user_birthday FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
bday = self.cursor.fetchone()
if not bday:
return None
elif 'user_birthday' not in bday:
return None
return bday['user_birthday']
def get_username(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT username_clean FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
data = self.cursor.fetchone()
if not data:
return ''
elif 'username_clean' not in data:
return ''
return data['username_clean']
def is_developer(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
# search into phpbb_groups
groups = self.get_user_groups()
for group in groups:
if group in self.DEVELOPER_GROUPS:
return True
return False
def is_administrator(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT user_type FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
data = self.cursor.fetchone()
if data:
if data['user_type'] == self.USER_FOUNDER:
return True
# search into phpbb_groups
groups = self.get_user_groups()
for group in groups:
if group in self.ADMIN_GROUPS:
return True
return False
def is_moderator(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
# search into phpbb_groups
groups = self.get_user_groups()
for group in groups:
if group in self.MODERATOR_GROUPS:
return True
return False
def is_user(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
if self.is_moderator():
return False
elif self.is_administrator():
return False
elif self.is_developer():
return False
self.cursor.execute('SELECT user_type,user_id FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
data = self.cursor.fetchone()
if not data:
return False
if self.is_user_banned(data['user_id']):
return False
elif data['user_type'] in [self.USER_NORMAL]:
return True
return False
# user == user_id
def is_user_banned(self, user):
self.check_connection()
self.cursor.execute('SELECT ban_userid FROM '+self.TABLE_PREFIX+'banlist WHERE ban_userid = %s', (user,))
data = self.cursor.fetchone()
if data:
return True
return False
def is_in_group(self, group):
self.check_connection()
self.check_login_data()
self.check_logged_in()
groups = self.get_user_groups()
if isinstance(group, int):
if group in groups:
return True
elif const_isstring(group):
self.cursor.execute('SELECT group_id FROM '+self.TABLE_PREFIX+'groups WHERE group_name = %s', (group,))
data = self.cursor.fetchone()
if not data:
return False
elif data['group_id'] in groups:
return True
return False
def get_user_groups(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT '+self.TABLE_PREFIX+'user_group.group_id,'+self.TABLE_PREFIX+'groups.group_name FROM '+self.TABLE_PREFIX+'user_group,'+self.TABLE_PREFIX+'users,'+self.TABLE_PREFIX+'groups WHERE '+self.TABLE_PREFIX+'users.user_id = %s and '+self.TABLE_PREFIX+'users.user_id = '+self.TABLE_PREFIX+'user_group.user_id and '+self.TABLE_PREFIX+'user_group.group_id = '+self.TABLE_PREFIX+'groups.group_id', (self.login_data['user_id'],))
data = self.cursor.fetchall()
mydata = {}
for mydict in data:
mydata[mydict['group_id']] = mydict['group_name']
return mydata
def get_user_group(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT group_id FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
data = self.cursor.fetchone()
if data:
if 'group_id' in data:
return data['group_id']
return -1
def get_user_id(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
return self.login_data['user_id']
def get_permission_data(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT user_permissions FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
return self.cursor.fetchone()
def update_email(self, email):
self.check_connection()
self.check_login_data()
self.check_logged_in()
email_hash = self._generate_email_hash(email)
mydata = {
'user_email_hash': email_hash,
'user_email': email.lower(),
}
try:
sql = self._generate_sql("update", self.TABLE_PREFIX+'users', mydata, 'user_id = %s' % (self.login_data['user_id'],))
self.cursor.execute(sql)
return True
except Exception:
return False
def update_password_hash(self, password_hash):
self.check_connection()
self.check_login_data()
self.check_logged_in()
mydata = {
'user_password': password_hash,
}
try:
sql = self._generate_sql("update", self.TABLE_PREFIX+'users', mydata, 'user_id = %s' % (self.login_data['user_id'],))
self.cursor.execute(sql)
return True
except Exception:
return False
def get_email(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self.cursor.execute('SELECT user_email FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
data = self.cursor.fetchone()
if not data:
return ''
elif 'user_email' not in data:
return ''
return data['user_email']
def update_user_id_profile(self, profile_data):
self.check_connection()
self.check_login_data()
self.check_logged_in()
# filter valid params
valid_params = [
"user_icq", "user_yim", "user_msnm",
"user_jabber", "user_website", "user_from",
"user_interests", "user_occ", "user_birthday",
"user_sig"
]
my_params = {}
for param in valid_params:
d = profile_data.get(param)
if d is None:
continue
my_params[param] = d
if not my_params:
return False, 'no parameters'
# validate parameters
b_day = my_params.get('user_birthday')
if const_isstring(b_day):
import re
myre = re.compile("(0[1-9]|[12][0-9]|3[01])[-](0[1-9]|1[012])[-](19|20)\d\d")
if not myre.match(b_day):
del my_params['user_birthday']
try:
sql = self._generate_sql("update", self.TABLE_PREFIX+'users', my_params, 'user_id = %s' % (self.login_data['user_id'],))
self.cursor.execute(sql)
return True, None
except Exception as e:
return False, str(e)
def _set_config_value(self, config_name, data):
self.cursor.execute('UPDATE '+self.TABLE_PREFIX+'config SET config_value = %s WHERE config_name = %s', (data, config_name,))
def _get_config_value(self, config_name):
self.check_connection()
self.cursor.execute('SELECT config_value FROM '+self.TABLE_PREFIX+'config WHERE config_name = %s', (config_name,))
myconfig = self.cursor.fetchone()
if isinstance(myconfig, dict):
if 'config_value' in myconfig:
return myconfig['config_value']
return None
def _update_session_table(self, user_id, ip_address):
self.check_connection()
time_now = int(time.time())
autologin = self._get_config_value("allow_autologin")
self.cursor.execute('SELECT user_allow_viewonline FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (user_id,))
myuserprefs = self.cursor.fetchone()
session_admin = 0
session_data = {
'session_id': None,
'session_user_id': user_id,
'session_last_visit': time_now,
'session_start': time_now,
'session_time': time_now,
'session_ip': ip_address,
'session_browser': self.USER_AGENT,
'session_forwarded_for': '',
'session_page': 'index.php',
'session_viewonline': myuserprefs['user_allow_viewonline'],
'session_autologin': autologin,
'session_admin': session_admin,
'session_forum_id': 0,
}
import hashlib
m = hashlib.md5()
m.update(str(user_id)+str(time_now)+str(self.USER_AGENT)+str(ip_address)+str(autologin)+str(myuserprefs['user_allow_viewonline']))
session_data['session_id'] = m.hexdigest()
self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'sessions WHERE session_user_id = %s', (user_id,))
mydata = self.cursor.fetchone()
do_update = False
if mydata:
do_update = True
# update
session_data['session_id'] = mydata['session_id']
session_data['session_viewonline'] = mydata['session_viewonline']
session_data['session_autologin'] = mydata['session_autologin']
session_data['session_forwarded_for'] = mydata['session_forwarded_for']
session_data['session_forum_id'] = mydata['session_forum_id']
session_data['session_page'] = mydata['session_page']
session_data['session_browser'] = mydata['session_browser']
session_data['session_admin'] = mydata['session_admin']
if do_update:
where = "session_id = '%s'" % (session_data['session_id'],)
del session_data['session_id']
sql = self._generate_sql('update', self.TABLE_PREFIX+'sessions', session_data, where)
else:
sql = self._generate_sql('insert', self.TABLE_PREFIX+'sessions', session_data)
if sql:
self.cursor.execute(sql)
self.dbconn.commit()
def _is_ip_banned(self, ip):
self.check_connection()
self.cursor.execute('SELECT ban_ip FROM '+self.TABLE_PREFIX+'banlist WHERE ban_ip = %s', (ip,))
data = self.cursor.fetchone()
if data:
return True
return False
def _get_unique_id(self):
import hashlib
m = hashlib.md5()
rnd = str(abs(hash(os.urandom(1))))
m.update(rnd)
x = m.hexdigest()[:-16]
del m
return x
def _get_random_number(self):
myrand = 0
low_n = 100000
high_n = 999999
while (myrand < low_n) or (myrand > high_n):
try:
myrand = hash(os.urandom(1))%high_n
except NotImplementedError:
random.seed()
myrand = random.randint(low_n, high_n)
return myrand
def _get_password_hash(self, password):
#random_state = self._get_unique_id()
myrandom = str(self._get_random_number())
myhash = self._hash_crypt_private(password, self._hash_gensalt_private(myrandom))
if len(myhash) == 34:
return myhash
import hashlib
m = hashlib.md5()
m.update(myhash)
return m.hexdigest()
def _hash_gensalt_private(self, myinput, iteration_count_log2 = 6):
if (iteration_count_log2 < 4) or (iteration_count_log2 > 31):
iteration_count_log2 = 8
myoutput = '$H$'
myoutput += self.itoa64[min(iteration_count_log2 + 5, 30)]
myoutput += self._hash_encode64(myinput, 6)
return myoutput
def _hash_crypt_private(self, password, setting):
myoutput = '*'
# Check for correct hash
if setting[:3] != '$H$':
return myoutput
count_log2 = self.itoa64.find(setting[3])
if count_log2 == -1:
count_log2 = 0
if (count_log2 < 7) or (count_log2 > 30):
return myoutput
count = 1 << count_log2
salt = setting[4:12]
if len(salt) != 8:
return myoutput
import hashlib
m = hashlib.md5()
m.update(salt+password)
myhash = m.digest()
while count:
m = hashlib.md5()
m.update(myhash+password)
myhash = m.digest()
count -= 1
myoutput = setting[:12]
myoutput += self._hash_encode64(myhash, 16)
return myoutput
def _hash_encode64(self, myinput, count):
output = ''
i = 0
while i < count:
value = ord(myinput[i])
i += 1
output += self.itoa64[value & 0x3f]
if i < count:
value |= ord(myinput[i]) << 8
output += self.itoa64[(value >> 6) & 0x3f]
if i >= count:
break
i += 1
if i < count:
value |= ord(myinput[i]) << 16
output += self.itoa64[(value >> 12) & 0x3f]
if (i >= count):
break
i += 1
output += self.itoa64[(value >> 18) & 0x3f]
return output
def _phpbb3_check_hash(self, password, myhash):
if len(myhash) == 34:
return self._hash_crypt_private(password, myhash) == myhash
import hashlib
m = hashlib.md5()
m.update(password)
rhash = m.hexdigest()
return rhash == myhash
@@ -1,115 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Authenticators Interface}.
"""
from entropy.const import const_get_stringtype
from entropy.services.auth_interfaces import phpBB3Auth
from entropy.services.skel import SocketAuthenticator
from entropy.exceptions import PermissionDenied
# Authenticator that can be used by SocketHostInterface based instances
class phpBB3(phpBB3Auth, SocketAuthenticator):
def __init__(self, HostInterface, *args, **kwargs):
SocketAuthenticator.__init__(self, HostInterface)
phpBB3Auth.__init__(self)
self.set_connection_data(kwargs)
self.connect()
def set_session(self, session):
self.session = session
session_data = self.HostInterface.sessions.get(self.session)
if not session_data:
return
auth_id = session_data['auth_uid']
if auth_id:
self.logged_in = True
# fill login_data with fake information
self.login_data = {
'username': self.FAKE_USERNAME,
'password': 'look elsewhere, this is not a password',
'user_id': auth_id
}
ip_address = session_data.get('ip_address')
if ip_address and self.do_update_session_table:
self._update_session_table(auth_id, ip_address)
def docmd_login(self, arguments):
# filter n00bs
if not arguments or (len(arguments) != 2):
return False, None, None, 'wrong arguments'
ip_address = None
session_data = self.HostInterface.sessions.get(self.session)
if session_data:
ip_address = session_data.get('ip_address')
user = arguments[0]
password = arguments[1]
if ip_address:
if self._is_ip_banned(ip_address):
return False, user, None, "banned IP"
login_data = {'username': user, 'password': password}
self.set_login_data(login_data)
rc = False
try:
rc = self.login()
except PermissionDenied as e:
return rc, user, None, e.value
if rc:
uid = self.get_user_id()
is_admin = self.is_administrator()
is_dev = self.is_developer()
is_mod = self.is_moderator()
is_user = self.is_user()
self.HostInterface.sessions[self.session]['admin'] = is_admin
self.HostInterface.sessions[self.session]['developer'] = is_dev
self.HostInterface.sessions[self.session]['moderator'] = is_mod
self.HostInterface.sessions[self.session]['user'] = is_user
if ip_address and uid and self.do_update_session_table:
self._update_session_table(uid, ip_address)
return True, user, uid, "ok"
return rc, user, None, "login failed"
# if we get here it means we are logged in
def docmd_userdata(self):
data = self.get_user_data()
return True, data, 'ok'
def docmd_logout(self, myargs):
# filter n00bs
if (len(myargs) < 1) or (len(myargs) > 1):
return False, None, 'wrong arguments'
user = myargs[0]
# filter n00bs
if not user or not isinstance(user, const_get_stringtype()):
return False, None, "wrong user"
if not self.is_logged_in():
return False, user, "already logged out"
return True, user, "ok"
def set_exc_permissions(self, *args, **kwargs):
pass
def hide_login_data(self, args):
myargs = args[:]
myargs[-1] = 'hidden'
return myargs
def terminate_instance(self):
self.disconnect()
-73
View File
@@ -1,73 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Command Interfaces}.
"""
from entropy.services.skel import SocketCommands
class phpBB3(SocketCommands):
def __init__(self, HostInterface):
SocketCommands.__init__(self, HostInterface, inst_name = "phpbb3-commands")
self.valid_commands = {
'is_user': {
'auth': True,
'built_in': False,
'cb': self.docmd_is_user,
'args': ["authenticator"],
'as_user': False,
'desc': "returns whether the username linked with the session belongs to a simple user",
'syntax': "<SESSION_ID> is_user",
'from': str(self), # from what class
},
'is_developer': {
'auth': True,
'built_in': False,
'cb': self.docmd_is_developer,
'args': ["authenticator"],
'as_user': False,
'desc': "returns whether the username linked with the session belongs to a developer",
'syntax': "<SESSION_ID> is_developer",
'from': str(self), # from what class
},
'is_moderator': {
'auth': True,
'built_in': False,
'cb': self.docmd_is_moderator,
'args': ["authenticator"],
'as_user': False,
'desc': "returns whether the username linked with the session belongs to a moderator",
'syntax': "<SESSION_ID> is_moderator",
'from': str(self), # from what class
},
'is_administrator': {
'auth': True,
'built_in': False,
'cb': self.docmd_is_administrator,
'args': ["authenticator"],
'as_user': False,
'desc': "returns whether the username linked with the session belongs to an administrator",
'syntax': "<SESSION_ID> is_administrator",
'from': str(self), # from what class
},
}
def docmd_is_user(self, authenticator):
return authenticator.is_user(), 'ok'
def docmd_is_developer(self, authenticator):
return authenticator.is_developer(), 'ok'
def docmd_is_administrator(self, authenticator):
return authenticator.is_administrator(), 'ok'
def docmd_is_moderator(self, authenticator):
return authenticator.is_moderator(), 'ok'
-31
View File
@@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Exceptions module}.
These are the exceptions raised by Entropy Services RPC system.
"""
from entropy.exceptions import EntropyException
class EntropyServicesError(EntropyException):
""" Generic Entropy Services exception. All classes here belong to this. """
class TransmissionError(EntropyServicesError):
""" Generic transmission error exception """
class BrokenPipe(TransmissionError):
""" Broken pipe transmission error """
class SSLTransmissionError(TransmissionError):
""" Error on SSL socket """
class ServiceConnectionError(EntropyServicesError):
"""Cannot connect to service"""
class TimeoutError(EntropyServicesError):
""" Timeout error """
File diff suppressed because it is too large Load Diff
@@ -1,368 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Repository Management Command Interface}.
"""
import os
from entropy.services.skel import SocketCommands
from entropy.const import etpConst
import entropy.tools
class Repository(SocketCommands):
def __init__(self, HostInterface):
SocketCommands.__init__(self, HostInterface, inst_name = "repository_server")
self.valid_commands = {
'repository_server:dbdiff': {
'auth': False,
'built_in': False,
'cb': self.docmd_dbdiff,
'args': ["myargs"],
'as_user': False,
'desc': "returns idpackage differences against the latest available repository",
'syntax': "<SESSION_ID> repository_server:dbdiff <repository> <arch> <product> <branch> [idpackages]",
'from': str(self), # from what class
},
'repository_server:pkginfo_strict': {
'auth': False,
'built_in': False,
'cb': self.docmd_pkginfo_strict,
'args': ["myargs"],
'as_user': False,
'desc': "returns metadata of the provided idpackages excluding 'content'",
'syntax': "<SESSION_ID> repository_server:pkginfo_strict <content fmt True/False> <repository> <arch> <product> <branch> <idpackage>",
'from': str(self), # from what class
},
'repository_server:treeupdates': {
'auth': False,
'built_in': False,
'cb': self.docmd_treeupdates,
'args': ["myargs"],
'as_user': False,
'desc': "returns repository treeupdates metadata",
'syntax': "<SESSION_ID> repository_server:treeupdates <repository> <arch> <product> <branch>",
'from': str(self), # from what class
},
'repository_server:get_package_sets': {
'auth': False,
'built_in': False,
'cb': self.docmd_package_sets,
'args': ["myargs"],
'as_user': False,
'desc': "returns repository package sets metadata",
'syntax': "<SESSION_ID> repository_server:get_package_sets <repository> <arch> <product> <branch>",
'from': str(self), # from what class
},
'repository_server:get_repository_metadata': {
'auth': False,
'built_in': False,
'cb': self.docmd_repository_metadata,
'args': ["myargs"],
'as_user': False,
'desc': "returns repository metadata (package sets, treeupdates, libraries <=> idpackages map)",
'syntax': "<SESSION_ID> repository_server:get_repository_metadata <repository> <arch> <product> <branch>",
'from': str(self), # from what class
}
}
def docmd_dbdiff(self, myargs):
if len(myargs) < 5:
return None
repository = myargs[0]
arch = myargs[1]
product = myargs[2]
try:
branch = str(myargs[3])
except (UnicodeEncodeError, UnicodeDecodeError,):
return None
foreign_idpackages = myargs[4:]
x = (repository, arch, product, branch,)
valid = self.HostInterface.is_repository_active(x)
if not valid:
return valid
dbpath = self.get_database_path(repository, arch, product, branch)
mtime = self.get_database_mtime(repository, arch, product, branch)
rev_id = self.get_database_revision(repository, arch, product, branch)
cached = self.HostInterface.get_dcache(
x + ('docmd_dbdiff', mtime, rev_id,), repository)
if cached is not None:
std_checksum, secure_checksum, myids = cached
else:
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
timeout = 1)
if not acquired:
return False
try:
dbconn = self.HostInterface.open_repository(dbpath,
docache = False)
std_checksum = dbconn.checksum(do_order = True, strict = False,
strings = True)
secure_checksum = dbconn.checksum(do_order = True,
strict = False, strings = True, include_signatures = True)
myids = dbconn.listAllPackageIds()
cached = std_checksum, secure_checksum, myids
self.HostInterface.set_dcache(
x + ('docmd_dbdiff', mtime, rev_id,), cached, repository)
dbconn.close()
finally:
self.HostInterface.master_slave_lock.slave_release(x)
foreign_idpackages = set(foreign_idpackages)
removed_ids = foreign_idpackages - myids
added_ids = myids - foreign_idpackages
data = {
'removed': removed_ids,
'added': added_ids,
'checksum': std_checksum,
'secure_checksum': secure_checksum,
}
return data
def docmd_repository_metadata(self, myargs):
if len(myargs) < 4:
return None
repository = myargs[0]
arch = myargs[1]
product = myargs[2]
try:
branch = str(myargs[3])
except (UnicodeEncodeError, UnicodeDecodeError,):
return None
x = (repository, arch, product, branch,)
valid = self.HostInterface.is_repository_active(x)
if not valid:
return valid
mtime = self.get_database_mtime(repository, arch, product, branch)
rev_id = self.get_database_revision(repository, arch, product, branch)
cached = self.HostInterface.get_dcache(
(repository, arch, product, branch, 'docmd_repository_metadata',
mtime, rev_id), repository)
if cached is not None:
return cached
metadata = {}
dbpath = self.get_database_path(repository, arch, product, branch)
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
timeout = 1)
if not acquired:
return False
try:
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
metadata['sets'] = dbconn.retrievePackageSets()
metadata['treeupdates_actions'] = dbconn.listAllTreeUpdatesActions()
metadata['treeupdates_digest'] = \
dbconn.retrieveRepositoryUpdatesDigest(repository)
# NOTE: kept for backward compatibility (<=0.99.0.x) remove in future
metadata['library_idpackages'] = []
metadata['revision'] = self.get_database_revision(repository, arch,
product, branch)
dbconn.close()
finally:
self.HostInterface.master_slave_lock.slave_release(x)
self.HostInterface.set_dcache(
(repository, arch, product, branch, 'docmd_repository_metadata',
mtime, rev_id,), metadata, repository)
return metadata
def docmd_package_sets(self, myargs):
if len(myargs) < 4:
return None
repository = myargs[0]
arch = myargs[1]
product = myargs[2]
try:
branch = str(myargs[3])
except (UnicodeEncodeError, UnicodeDecodeError,):
return None
x = (repository, arch, product, branch,)
valid = self.HostInterface.is_repository_active(x)
if not valid:
return valid
mtime = self.get_database_mtime(repository, arch, product, branch)
rev_id = self.get_database_revision(repository, arch, product, branch)
cached = self.HostInterface.get_dcache(
(repository, arch, product, branch, 'docmd_package_sets',
mtime, rev_id,), repository)
if cached is not None:
return cached
dbpath = self.get_database_path(repository, arch, product, branch)
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
timeout = 1)
if not acquired:
return False
try:
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
data = dbconn.retrievePackageSets()
dbconn.close()
finally:
self.HostInterface.master_slave_lock.slave_release(x)
self.HostInterface.set_dcache(
(repository, arch, product, branch, 'docmd_package_sets',
mtime, rev_id,), data, repository)
return data
def docmd_treeupdates(self, myargs):
if len(myargs) < 4:
return None
repository = myargs[0]
arch = myargs[1]
product = myargs[2]
try:
branch = str(myargs[3])
except (UnicodeEncodeError, UnicodeDecodeError,):
return None
x = (repository, arch, product, branch,)
valid = self.HostInterface.is_repository_active(x)
if not valid:
return valid
mtime = self.get_database_mtime(repository, arch, product, branch)
rev_id = self.get_database_revision(repository, arch, product, branch)
cached = self.HostInterface.get_dcache(
(repository, arch, product, branch, 'docmd_treeupdates', mtime,
rev_id), repository)
if cached is not None:
return cached
dbpath = self.get_database_path(repository, arch, product, branch)
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
timeout = 1)
if not acquired:
return False
try:
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
data = {}
data['actions'] = dbconn.listAllTreeUpdatesActions()
data['digest'] = dbconn.retrieveRepositoryUpdatesDigest(repository)
dbconn.close()
dbconn = None
finally:
self.HostInterface.master_slave_lock.slave_release(x)
self.HostInterface.set_dcache(
(repository, arch, product, branch, 'docmd_treeupdates', mtime,
rev_id,), data, repository)
return data
def docmd_pkginfo_strict(self, myargs):
if len(myargs) < 6:
return None
format_content_for_insert = myargs[0]
if not isinstance(format_content_for_insert, bool):
format_content_for_insert = False
repository = myargs[1]
arch = myargs[2]
product = myargs[3]
try:
branch = str(myargs[4])
except (UnicodeEncodeError, UnicodeDecodeError,):
return None
zidpackages = myargs[5:]
idpackages = []
for idpackage in zidpackages:
if isinstance(idpackage, int):
idpackages.append(idpackage)
if not idpackages:
return None
idpackages = tuple(sorted(idpackages))
x = (repository, arch, product, branch,)
valid = self.HostInterface.is_repository_active(x)
if not valid:
return valid
mtime = self.get_database_mtime(repository, arch, product, branch)
rev_id = self.get_database_revision(repository, arch, product, branch)
cached = self.HostInterface.get_dcache(
(repository, arch, product, branch, idpackages,
'docmd_pkginfo_strict', mtime, rev_id),
repository)
if cached is not None:
return cached
dbpath = self.get_database_path(repository, arch, product, branch)
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
timeout = 1)
if not acquired:
return False
try:
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
result = {}
for idpackage in idpackages:
try:
mydata = dbconn.getPackageData(
idpackage,
content_insert_formatted = format_content_for_insert,
get_content = False, get_changelog = False
)
except Exception:
tb = entropy.tools.get_traceback()
print(tb)
self.HostInterface.socketLog.write(tb)
dbconn.close()
return None
result[idpackage] = mydata.copy()
dbconn.close()
finally:
self.HostInterface.master_slave_lock.slave_release(x)
self.HostInterface.set_dcache(
(repository, arch, product, branch, idpackages,
'docmd_pkginfo_strict', mtime, rev_id,),
result, repository)
return result
def get_database_path(self, repository, arch, product, branch):
repoitems = (repository, arch, product, branch,)
mydbroot = self.HostInterface.repositories[repoitems]['dbpath']
dbpath = os.path.join(mydbroot, etpConst['etpdatabasefile'])
return dbpath
def get_database_mtime(self, repository, arch, product, branch):
dbpath = self.get_database_path(repository, arch, product, branch)
try:
mtime = os.path.getmtime(dbpath)
except (OSError, IOError,):
mtime = 0.0
return mtime
def get_database_revision(self, repository, arch, product, branch):
x = (repository, arch, product, branch,)
try:
return int(self.HostInterface.repositories[x]['dbrevision'])
except ValueError:
return -1
@@ -1,315 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Repository Management Interface}.
"""
import os
import errno
import threading
import shutil
from entropy.core.settings.base import SystemSettings
from entropy.output import TextInterface, blue, brown, darkred, teal
from entropy.const import etpConst
from entropy.misc import TimeScheduled, MasterSlaveLock
from entropy.cache import EntropyCacher
from entropy.services.interfaces import SocketHost
from entropy.services.repository.commands import Repository
from entropy.client.interfaces import Client
import entropy.dump
import entropy.tools
class Server(SocketHost):
CACHE_ID = 'reposerver/item'
class ServiceInterface(TextInterface):
def __init__(self, *args, **kwargs):
pass
def __init__(self, repositories, repository_lock_scanner = True,
do_ssl = False, stdout_logging = True, **kwargs):
self.master_slave_lock = MasterSlaveLock()
# instantiate critical constants
etpConst['socket_service']['max_connections'] = 5000
self.__repository_commands_class = Repository
self._entropy = Client(installed_repo = -1)
self.__cacher = EntropyCacher()
self.__lock_scanner = None
self.__dbcache = {}
# setup System Settings
self._settings = SystemSettings()
self._settings['socket_service']['max_connections'] = 5000
etpConst['socketloglevel'] = 1
if 'external_cmd_classes' not in kwargs:
kwargs['external_cmd_classes'] = []
if repository_lock_scanner:
kwargs['external_cmd_classes'].insert(0,
self.__repository_commands_class)
SocketHost.__init__(
self,
Server.ServiceInterface,
installed_repo = -1,
sock_output = self._entropy,
ssl = do_ssl,
**kwargs
)
self.stdout_logging = stdout_logging
self.repositories = repositories.copy()
self._expand_repositories()
if repository_lock_scanner:
# start timed lock file scanning
self._start_repository_lock_scanner()
def killall(self):
SocketHost.killall(self)
if self.__lock_scanner != None:
self.__lock_scanner.kill()
def is_repository_active(self, repo_tuple):
if repo_tuple not in self.repositories:
return None
if self.repositories[repo_tuple]['fatal_error']:
return False
# is repository being updated
if self.repositories[repo_tuple]['locked']:
return False
# repository database does not exist
if not self.repositories[repo_tuple]['enabled']:
return False
return True
def get_dcache(self, item, repo = '_norepo_'):
return entropy.dump.loadobj(Server.CACHE_ID+"/"+repo+"/"+str(hash(item)))
def set_dcache(self, item, data, repo = '_norepo_'):
entropy.dump.dumpobj(Server.CACHE_ID+"/"+repo+"/"+str(hash(item)), data)
def close_repository(self, dbpath):
try:
dbc = self.__dbcache.pop(dbpath)
dbc.close()
except KeyError:
pass
def open_repository(self, dbpath, docache = True):
if docache:
cached = self.__dbcache.get(dbpath)
if cached != None:
return cached
dbc = self._entropy.open_generic_repository(
dbpath,
xcache = False,
read_only = True,
skip_checks = True
)
if docache:
self.__dbcache[dbpath] = dbc
return dbc
def _start_repository_lock_scanner(self):
self.__lock_scanner = TimeScheduled(10, self.__lock_scan)
self.__lock_scanner.start()
def _is_repository_available(self, repo_tuple):
if self.repositories[repo_tuple]['fatal_error']:
return False
xxx, yyy, compressed_dbpath = self.__get_unpack_metadata(repo_tuple)
if not os.path.exists(compressed_dbpath):
return False
return True
def __get_unpack_metadata(self, repo_tuple):
cmethod = self.repositories[repo_tuple]['cmethod']
cmethod_data = etpConst['etpdatabasecompressclasses'].get(
cmethod)
unpack_method = cmethod_data[1]
compressed_dbfile = etpConst[cmethod_data[2]]
compressed_dbpath = os.path.join(
self.repositories[repo_tuple]['dbpath'], compressed_dbfile)
return cmethod, unpack_method, compressed_dbpath
def __unpack_repository(self, db_path, repo_tuple):
cmethod, unpack_method, compressed_dbpath = self.__get_unpack_metadata(
repo_tuple)
try:
unpack_func = getattr(entropy.tools, unpack_method, None)
except (IOError, OSError):
return False
if unpack_func is None:
return False
generated_outpath = unpack_func(compressed_dbpath)
if db_path != generated_outpath:
try:
os.rename(generated_outpath, db_path)
except OSError:
shutil.move(generated_outpath, db_path)
return True
def __drop_cache_now(self, repo):
return EntropyCacher.clear_cache_item(Server.CACHE_ID+"/"+repo+"/")
def __lock_scan(self):
do_clear = set()
for repository, arch, product, branch in self.repositories:
repo_tuple = (repository, arch, product, branch,)
db_path = os.path.join(self.repositories[repo_tuple]['dbpath'],
etpConst['etpdatabasefile'])
available = self._is_repository_available(repo_tuple)
if not available:
if self.repositories[repo_tuple]['enabled']:
self.repositories[repo_tuple]['enabled'] = False
self.close_repository(db_path)
do_clear.add(repository)
continue
signal_file = os.path.join(self.repositories[repo_tuple]['dbpath'],
etpConst['etpdatabaseeapi3updates'])
if os.path.lexists(signal_file) or \
self.repositories[repo_tuple]['locked']:
# make sure to mark it as locked
self.repositories[repo_tuple]['locked'] = True
# acquire write lock
self.master_slave_lock.master_acquire(repo_tuple)
try:
self.close_repository(db_path)
do_clear.add(repository)
mytxt = blue("%s.") % (
"repository is now locked, there is something new!",)
self.output(
"[%s] %s" % (
brown(str(repo_tuple)),
mytxt,
),
importance = 1,
level = "info"
)
status = self.__unpack_repository(db_path, repo_tuple)
if status:
mytxt = blue("%s. %s:") % (
"unlocking and indexing database",
"hash",
)
self.output(
"[%s] %s" % (
brown(str(repo_tuple)),
mytxt,
),
importance = 1,
level = "info"
)
# update revision
self.repositories[repo_tuple]['dbrevision'] = \
self.__read_revision(repo_tuple)
dbc = self.open_repository(db_path, docache = False)
dbc.createAllIndexes()
db_ck = dbc.checksum(do_order = True, strict = False,
strings = True)
self.output(
teal(str(db_ck)),
importance = 1,
level = "info"
)
dbc.close()
self.__cacher.discard()
self.__drop_cache_now(repository)
self.repositories[repo_tuple]['locked'] = False
self.repositories[repo_tuple]['enabled'] = True
else:
mytxt = darkred("%s.") % (
"error during repository unpack, disabling repository",)
self.output(
"[%s] %s" % (
brown(str(repo_tuple)),
mytxt,
),
importance = 1,
level = "info"
)
self.repositories[repo_tuple]['fatal_error'] = True
self.repositories[repo_tuple]['enabled'] = False
self.repositories[repo_tuple]['locked'] = False
finally:
try:
os.remove(signal_file)
except OSError as err:
if err.errno != errno.ENOENT:
raise
self.master_slave_lock.master_release(repo_tuple)
else:
# if repository is not locked and signal file is not found
# consider the repository enabled.
self.repositories[repo_tuple]['enabled'] = True
self.__cacher.discard()
for repo in do_clear:
self.__drop_cache_now(repo)
def __read_revision(self, repo_tuple):
db_dir = self.repositories[repo_tuple]['dbpath']
rev_file = os.path.join(db_dir, etpConst['etpdatabaserevisionfile'])
myrev = '0'
if os.path.isfile(rev_file) and os.access(rev_file, os.R_OK):
with open(rev_file, "r") as f:
try:
myrev = str(int(f.readline().strip()))
except ValueError:
myrev = '-1'
return myrev
def _expand_repositories(self):
for repository, arch, product, branch in self.repositories:
x = (repository, arch, product, branch,)
if 'cmethod' not in self.repositories[x]:
raise AttributeError("cmethod not specified for: %s" % (x,))
if self.repositories[x]['cmethod'] not in \
etpConst['etpdatabasesupportedcformats']:
raise AttributeError("wrong cmethod for: %s" % (x,))
# repository is locked by default, its db needs to be unpacked
self.repositories[x]['locked'] = True
# repository can become faulty (inability of unpacking data, etc)
# and run into unrecoverable errors
self.repositories[x]['fatal_error'] = False
db_path = os.path.join(self.repositories[x]['dbpath'],
etpConst['etpdatabasefile'])
if os.path.isfile(db_path) and os.access(db_path, os.R_OK):
self.repositories[x]['enabled'] = True
else:
self.repositories[x]['enabled'] = False
self.repositories[x]['dbrevision'] = self.__read_revision(x)
-419
View File
@@ -1,419 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Stub Interfaces}.
"""
import os
from entropy.const import const_convert_to_unicode
from entropy.exceptions import PermissionDenied, LibraryNotFound
from entropy.services.exceptions import ServiceConnectionError
from entropy.i18n import _
class SocketCommands:
def __str__(self):
return self.inst_name
inst_name = 'command-skel'
def __init__(self, HostInterface, inst_name = 'command-skel'):
self.HostInterface = HostInterface
self.no_acked_commands = []
self.termination_commands = []
self.initialization_commands = []
self.login_pass_commands = []
self.no_session_commands = []
self.raw_commands = []
self.config_commands = []
self.valid_commands = set()
self.inst_name = inst_name
def register(
self,
valid_commands,
no_acked_commands,
termination_commands,
initialization_commands,
login_pass_commads,
no_session_commands,
raw_commands,
config_commands
):
valid_commands.update(self.valid_commands)
no_acked_commands.extend(self.no_acked_commands)
termination_commands.extend(self.termination_commands)
initialization_commands.extend(self.initialization_commands)
login_pass_commads.extend(self.login_pass_commands)
no_session_commands.extend(self.no_session_commands)
raw_commands.extend(self.raw_commands)
config_commands.extend(self.config_commands)
class SocketAuthenticator:
"""
Base class for Entropy SocketHost RPC authentication.
"""
def __init__(self, HostInterface):
self.HostInterface = HostInterface
self.session = None
def set_session(self, session):
"""
Set Entropy SocketHost connection session id.
@param session: connection session
@type session: int
"""
self.session = session
def hide_login_data(self, args):
"""
Given Entropy SocketHost RPC login command in list form, hide password
data (which is going to be stored in log file).
NOTE: this method MUST be reimplemented
@param args: arguments of RPC login command
@type args: list
@return: filtered list
@rtype: list
"""
raise NotImplementedError()
def set_exc_permissions(self, uid, gid):
"""
Set execution permissions (setuid, setgid) for the running process.
@param uid: user id
@type: int
@param gid: group id
@type: int
"""
if gid != None:
os.setgid(gid)
if uid != None:
os.setuid(uid)
def terminate_instance(self):
"""
This function is called when the Authenticator is going to be destroyed.
You can reimplement this to execute arbitrary code (for eg. terminate
a database connection).
NOTE: there is no need to reimplement this if you are not using any
fancy stuff.
"""
pass
class RemoteDatabase:
def escape_fake(self, mystr):
return mystr
def __init__(self):
self.dbconn = None
self.cursor = None
self.plain_cursor = None
self.escape_string = self.escape_fake
self.connection_data = {}
try:
import MySQLdb, _mysql_exceptions
from MySQLdb.constants import FIELD_TYPE
from MySQLdb.converters import conversions
except ImportError:
raise LibraryNotFound('LibraryNotFound: dev-python/mysql-python not found')
self.mysql = MySQLdb
self.mysql_exceptions = _mysql_exceptions
self.FIELD_TYPE = FIELD_TYPE
self.conversion_dict = conversions.copy()
self.conversion_dict[self.FIELD_TYPE.DECIMAL] = int
self.conversion_dict[self.FIELD_TYPE.LONG] = int
self.conversion_dict[self.FIELD_TYPE.FLOAT] = float
self.conversion_dict[self.FIELD_TYPE.NEWDECIMAL] = float
def check_connection(self):
if self.dbconn == None:
raise ServiceConnectionError("not connected to service")
self._check_needed_reconnect()
def _check_needed_reconnect(self):
if self.dbconn == None:
return
try:
self.dbconn.ping()
except self.mysql_exceptions.OperationalError as e:
if e[0] != 2006:
raise
else:
self.connect()
return True
return False
def _raise_not_implemented_error(self):
raise NotImplementedError('NotImplementedError: %s' % (_('method not implemented'),))
def set_connection_data(self, data):
self.connection_data = data.copy()
if 'converters' not in self.connection_data and self.conversion_dict:
self.connection_data['converters'] = self.conversion_dict.copy()
def connect(self):
kwargs = {}
keys = [
('host', "hostname"),
('user', "username"),
('passwd', "password"),
('db', "dbname"),
('port', "port"),
('conv', "converters"), # mysql type converter dict
]
for ckey, dkey in keys:
if dkey not in self.connection_data:
continue
kwargs[ckey] = self.connection_data.get(dkey)
try:
self.dbconn = self.mysql.connect(**kwargs)
except self.mysql_exceptions.OperationalError as e:
raise ServiceConnectionError(repr(e))
self.plain_cursor = self.dbconn.cursor()
self.cursor = self.mysql.cursors.DictCursor(self.dbconn)
self.escape_string = self.dbconn.escape_string
return True
def disconnect(self):
self.check_connection()
self.escape_string = self.escape_fake
if hasattr(self.cursor, 'close'):
self.cursor.close()
if hasattr(self.dbconn, 'close'):
self.dbconn.close()
self.dbconn = None
self.cursor = None
self.plain_cursor = None
self.connection_data.clear()
return True
def commit(self):
self.check_connection()
return self.dbconn.commit()
def execute_script(self, myscript):
pty = None
for line in myscript.split(";"):
line = line.strip()
if not line:
continue
pty = self.cursor.execute(line)
return pty
def execute_query(self, *args):
return self.cursor.execute(*args)
def execute_many(self, query, myiter):
return self.cursor.executemany(query, myiter)
def fetchone(self):
return self.cursor.fetchone()
def fetchall(self):
return self.cursor.fetchall()
def fetchmany(self, *args, **kwargs):
return self.cursor.fetchmany(*args, **kwargs)
def lastrowid(self):
return self.cursor.lastrowid
def table_exists(self, table):
self.check_connection()
self.cursor.execute("show tables like %s", (table,))
rslt = self.cursor.fetchone()
if rslt:
return True
return False
def column_in_table_exists(self, table, column):
t_ex = self.table_exists(table)
if not t_ex:
return False
self.cursor.execute("show columns from "+table)
data = self.cursor.fetchall()
for row in data:
if row['Field'] == column:
return True
return False
def fetchall2set(self, item):
mycontent = set()
for x in item:
mycontent |= set(x)
return mycontent
def fetchall2list(self, item):
content = []
for x in item:
content += list(x)
return content
def fetchone2list(self, item):
return list(item)
def fetchone2set(self, item):
return set(item)
def _generate_sql(self, action, table, data, where = ''):
sql = ''
keys = sorted(data.keys())
if action == "update":
sql += 'UPDATE %s SET ' % (self.escape_string(table),)
keys_data = []
for key in keys:
keys_data.append("%s = '%s'" % (
self.escape_string(key),
self.escape_string(
const_convert_to_unicode(data[key], 'utf-8').encode('utf-8')).decode('utf-8')
)
)
sql += ', '.join(keys_data)
sql += ' WHERE %s' % (where,)
elif action == "insert":
sql = 'INSERT INTO %s (%s) VALUES (%s)' % (
self.escape_string(table),
', '.join([self.escape_string(x) for x in keys]),
', '.join(["'" + \
self.escape_string(
const_convert_to_unicode(data[x], 'utf-8').encode('utf-8')).decode('utf-8') + \
"'" for x in keys])
)
return sql
class Authenticator:
def __init__(self):
self.login_data = {}
self.logged_in = False
def check_login(self):
if not self.logged_in:
raise PermissionDenied("not logged in")
def set_login_data(self, data):
self.login_data = data.copy()
def check_login_data(self):
if not self.login_data:
raise PermissionDenied("no login data")
def check_logged_in(self):
if not self.is_logged_in():
raise PermissionDenied("not logged in")
def _raise_not_implemented_error(self):
raise NotImplementedError("not implemented")
def check_connection(self):
pass
def login(self):
self.check_connection()
self.check_login_data()
self._raise_not_implemented_error()
self.logged_in = True
return True
def logout(self):
self.check_connection()
self.check_login_data()
self._raise_not_implemented_error()
return True
def is_developer(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return True
def is_administrator(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return True
def is_moderator(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return True
def is_user(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return True
def is_user_banned(self, user):
self.check_connection()
self._raise_not_implemented_error()
return False
def is_in_group(self, group):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return True
def get_user_groups(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return {}
def get_user_group(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return -1
def get_user_id(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return -1
def is_logged_in(self):
return self.logged_in
def get_permission_data(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return {}
def get_user_data(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return {}
def get_username(self):
self.check_connection()
self.check_login_data()
self.check_logged_in()
self._raise_not_implemented_error()
return {}
@@ -1,41 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Testing Command Interface}.
"""
from entropy.services.skel import SocketCommands
class Test(SocketCommands):
def __init__(self, HostInterface):
SocketCommands.__init__(self, HostInterface, inst_name = "test-commands")
self.raw_commands = ['test:echo']
self.valid_commands = {
'test:echo': {
'auth': False,
'built_in': False,
'cb': self.docmd_echo,
'args': ["myargs"],
'as_user': False,
'desc': "print arguments echo",
'syntax': "<SESSION_ID> test:echo <raw_data>",
'from': str(self),
},
}
def docmd_echo(self, myargs):
if not myargs:
return None, 'wrong arguments'
return True, ' '.join(myargs)
@@ -1,41 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services Testing Interface}.
"""
from entropy.services.interfaces import SocketHost
from entropy.output import TextInterface
class Server(SocketHost):
class FakeServiceInterface:
def __init__(self, *args, **kwargs):
self.Text = TextInterface()
self.Text.output(":: FakeServiceInterface loaded ::")
def __init__(self, do_ssl = False, stdout_logging = True,
entropy_interface_kwargs = None, **kwargs):
if entropy_interface_kwargs is None:
entropy_interface_kwargs = {}
from entropy.services.system.commands import Base
if 'external_cmd_classes' not in kwargs:
kwargs['external_cmd_classes'] = []
kwargs['external_cmd_classes'].insert(0, Base)
self.Text = TextInterface()
SocketHost.__init__(
self,
self.FakeServiceInterface,
sock_output = self.Text,
ssl = do_ssl,
**kwargs
)
self.stdout_logging = stdout_logging
-834
View File
@@ -1,834 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Services UGC Base Command Interface}.
"""
import os
import shutil
from entropy.services.skel import SocketCommands
from entropy.const import etpConst, const_get_stringtype
from entropy.services.ugc.interfaces import Server
from entropy.misc import EmailSender
import entropy.tools
class UGC(SocketCommands):
ERROR_REPORT_MAIL = os.environ.get('ETP_ERROR_REPORT_MAIL',
'website@sabayon.org')
if not entropy.tools.is_valid_email(ERROR_REPORT_MAIL):
raise AttributeError("ETP_ERROR_REPORT_MAIL is bad")
SENDER_EMAIL_FALLBACK = os.environ.get('ETP_SENDER_EMAIL_FALLBACK',
'www-data@sabayon.org')
if not entropy.tools.is_valid_email(SENDER_EMAIL_FALLBACK):
raise AttributeError("ETP_SENDER_EMAIL_FALLBACK is bad")
def __init__(self, HostInterface, connection_data, store_path, store_url):
SocketCommands.__init__(self, HostInterface, inst_name = "ugc-commands")
self.connection_data = connection_data.copy()
self.store_path = store_path
self.store_url = store_url
self.DOC_TYPES = etpConst['ugc_doctypes'].copy()
self.SUPPORTED_DOCFILE_TYPES = [
self.DOC_TYPES['image'],
self.DOC_TYPES['generic_file'],
self.DOC_TYPES['youtube_video'],
]
self.raw_commands = [
'ugc:add_comment', 'ugc:edit_comment',
'ugc:register_stream', 'ugc:do_download_stats',
'ugc:report_error'
]
self.valid_commands = {
'ugc:get_comments': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_comments,
'args': ["myargs"],
'as_user': False,
'desc': "get the comments of the provided package key",
'syntax': "<SESSION_ID> ugc:get_comments app-foo/foo",
'from': str(self), # from what class
},
'ugc:get_comments_by_identifiers': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_comments_by_identifiers,
'args': ["myargs"],
'as_user': False,
'desc': "get the comments belonging to the provided identifiers",
'syntax': "<SESSION_ID> ugc:get_comments_by_identifiers <identifier1> <identifier2> <identifier3>",
'from': str(self), # from what class
},
'ugc:get_documents_by_identifiers': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_documents_by_identifiers,
'args': ["myargs"],
'as_user': False,
'desc': "get the documents belonging to the provided identifiers",
'syntax': "<SESSION_ID> ugc:get_documents_by_identifiers <identifier1> <identifier2> <identifier3>",
'from': str(self), # from what class
},
'ugc:get_vote': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_vote,
'args': ["myargs"],
'as_user': False,
'desc': "get the vote of the provided package key",
'syntax': "<SESSION_ID> ugc:get_vote app-foo/foo",
'from': str(self), # from what class
},
'ugc:get_downloads': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_downloads,
'args': ["myargs"],
'as_user': False,
'desc': "get the number of downloads of the provided package key",
'syntax': "<SESSION_ID> ugc:get_downloads app-foo/foo",
'from': str(self), # from what class
},
'ugc:get_textdocs': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_textdocs,
'args': ["myargs"],
'as_user': False,
'desc': "get the text documents belonging to the provided package key",
'syntax': "<SESSION_ID> ugc:get_textdocs app-foo/foo",
'from': str(self), # from what class
},
'ugc:get_textdocs_by_identifiers': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_textdocs_by_identifiers,
'args': ["myargs"],
'as_user': False,
'desc': "get the text documents belonging to the provided identifiers",
'syntax': "<SESSION_ID> ugc:get_textdocs_by_identifiers <identifier1> <identifier2> <identifier3>",
'from': str(self), # from what class
},
'ugc:get_alldocs': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_alldocs,
'args': ["myargs"],
'as_user': False,
'desc': "get the all the documents belonging to the provided package key",
'syntax': "<SESSION_ID> ugc:get_alldocs app-foo/foo",
'from': str(self), # from what class
},
'ugc:get_allvotes': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_allvotes,
'args': [],
'as_user': False,
'desc': "get vote information for every available package key",
'syntax': "<SESSION_ID> ugc:get_allvotes",
'from': str(self), # from what class
},
'ugc:get_alldownloads': {
'auth': False,
'built_in': False,
'cb': self.docmd_get_alldownloads,
'args': [],
'as_user': False,
'desc': "get download information for every available package key",
'syntax': "<SESSION_ID> ugc:get_alldownloads",
'from': str(self), # from what class
},
'ugc:do_vote': {
'auth': True,
'built_in': False,
'cb': self.docmd_do_vote,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "vote the specified application (from 0 to 5)",
'syntax': "<SESSION_ID> ugc:do_vote app-foo/foo <0..5>",
'from': str(self), # from what class
},
'ugc:add_comment': {
'auth': True,
'built_in': False,
'cb': self.docmd_add_comment,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "insert a comment related to a package key",
'syntax': "<SESSION_ID> ugc:add_comment app-foo/foo <valid xml formatted data>",
'from': str(self), # from what class
},
'ugc:remove_comment': {
'auth': True,
'built_in': False,
'cb': self.docmd_remove_comment,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "remove a comment (you need its iddoc and mod/admin privs)",
'syntax': "<SESSION_ID> ugc:remove_comment <iddoc>",
'from': str(self), # from what class
},
'ugc:edit_comment': {
'auth': True,
'built_in': False,
'cb': self.docmd_edit_comment,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "edit a comment related to a package key (you need its iddoc, mod/admin privs or being the author)",
'syntax': "<SESSION_ID> ugc:edit_comment <iddoc> <valid xml formatted data>",
'from': str(self), # from what class
},
'ugc:register_stream': {
'auth': True,
'built_in': False,
'cb': self.docmd_register_stream,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "register an uploaded file (through stream cmd) to the relative place (image, file, videos)",
'syntax': "<SESSION_ID> ugc:register_stream app-foo/foo <valid xml formatted data>",
'from': str(self), # from what class
},
'ugc:remove_image': {
'auth': True,
'built_in': False,
'cb': self.docmd_remove_image,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "remove an image (you need its iddoc and mod/admin privs)",
'syntax': "<SESSION_ID> ugc:remove_image <iddoc>",
'from': str(self), # from what class
},
'ugc:remove_file': {
'auth': True,
'built_in': False,
'cb': self.docmd_remove_file,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "remove a file (you need its iddoc and mod/admin privs)",
'syntax': "<SESSION_ID> ugc:remove_file <iddoc>",
'from': str(self), # from what class
},
'ugc:remove_youtube_video': {
'auth': True,
'built_in': False,
'cb': self.docmd_remove_youtube_video,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "remove a youtube video (you need its iddoc and mod/admin privs)",
'syntax': "<SESSION_ID> ugc:remove_youtube_video <iddoc>",
'from': str(self), # from what class
},
'ugc:do_download_stats': {
'auth': False,
'built_in': False,
'cb': self.docmd_do_download_stats,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "send information regarding downloads and distribution used",
'syntax': "<SESSION_ID> ugc:do_download_stats <valid xml formatted data>",
'from': str(self), # from what class
},
'ugc:report_error': {
'auth': False,
'built_in': False,
'cb': self.docmd_do_report_error,
'args': ["authenticator", "myargs"],
'as_user': False,
'desc': "submit an Entropy Error Report",
'syntax': "<SESSION_ID> ugc:report_error <valid xml formatted data>",
'from': str(self), # from what class
},
}
def _load_ugc_interface(self):
return Server(self.connection_data, self.store_path, self.store_url)
def _get_userid(self, authenticator):
session_data = self.HostInterface.sessions.get(authenticator.session)
if not session_data:
return False
elif 'auth_uid' not in session_data:
return False
return session_data['auth_uid']
def _get_username(self, authenticator):
return authenticator.get_username()
def _get_session_file(self, authenticator):
session_data = self.HostInterface.sessions.get(authenticator.session)
if not session_data:
return False
elif 'stream_path' not in session_data:
return False
elif not session_data['stream_path']:
return False
mypath = session_data['stream_path']
if not (os.path.isfile(mypath) and os.access(mypath, os.R_OK)):
return False
return mypath
def _get_session_ip_address(self, authenticator):
session_data = self.HostInterface.sessions.get(authenticator.session)
if not session_data:
return None
elif 'ip_address' not in session_data:
return None
return session_data['ip_address']
def docmd_register_stream(self, authenticator, myargs):
if len(myargs) < 3:
return None, 'wrong arguments'
pkgkey = myargs[0]
xml_string = ' '.join(myargs[1:])
try:
mydict = entropy.tools.dict_from_xml(xml_string)
except Exception as e:
return None, "error: %s" % (e,)
if not ('doc_type' in mydict \
and 'title' in mydict \
and 'description' in mydict \
and 'keywords' in mydict \
and 'file_name' in mydict ):
return None, 'wrong dict arguments, xml must have 5 items with attr value -> doc_type, title, description, keywords, file_name'
doc_type = mydict.get('doc_type')
title = mydict.get('title')
description = mydict.get('description')
keywords = mydict.get('keywords')
file_name = mydict.get('file_name')
real_filename = mydict.get('real_filename')
try:
doc_type = int(doc_type)
except (ValueError,):
return None, 'wrong arguments (doc_type)'
if doc_type not in self.SUPPORTED_DOCFILE_TYPES:
return None, 'unsupported doc type (SUPPORTED_DOCFILE_TYPES)'
if not title:
title = 'No title'
if not description:
description = 'No description'
if not keywords:
keywords = ''
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return False, 'no session data available'
username = self._get_username(authenticator)
# get file path
stream_path = self._get_session_file(authenticator)
if not stream_path:
return False, 'no stream path available'
orig_stream_path = os.path.dirname(stream_path)
new_stream_path = orig_stream_path
scount = -1
while os.path.lexists(new_stream_path):
scount += 1
b_name = os.path.basename(stream_path)
b_name = "%s.%s" % (scount, b_name,)
new_stream_path = os.path.join(os.path.dirname(orig_stream_path), b_name)
if scount > 1000000:
return False, 'while loop interrupted while looking for new_stream_path'
shutil.move(stream_path, new_stream_path)
stream_path = new_stream_path
ugc = self._load_ugc_interface()
rslt = None, 'invalid doc type'
if doc_type == self.DOC_TYPES['image']:
rslt = ugc.insert_image(pkgkey, userid, username, stream_path, file_name, title, description, keywords)
elif doc_type == self.DOC_TYPES['generic_file']:
rslt = ugc.insert_file(pkgkey, userid, username, stream_path, file_name, title, description, keywords)
elif doc_type == self.DOC_TYPES['youtube_video']:
rslt = ugc.insert_youtube_video(pkgkey, userid, username, stream_path, real_filename, title, description, keywords)
ugc.commit()
return rslt
def docmd_add_comment(self, authenticator, myargs):
if len(myargs) < 2:
return None, 'wrong arguments'
pkgkey = myargs[0]
xml_string = ' '.join(myargs[1:])
try:
mydict = entropy.tools.dict_from_xml(xml_string)
except Exception as e:
return None, "error: %s" % (e,)
if not ('comment' in mydict and 'title' in mydict and 'keywords' in mydict):
return None, 'wrong dict arguments, xml must have 3 items with attr value -> comment, title, keywords'
comment = mydict.get('comment')
title = mydict.get('title')
keywords = mydict.get('keywords')
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return False, 'no session data available'
username = self._get_username(authenticator)
ugc = self._load_ugc_interface()
status, iddoc = ugc.insert_comment(pkgkey, userid, username, comment, title, keywords)
if not status:
t = 'unable to add comment'
if isinstance(iddoc, const_get_stringtype()):
t = iddoc
return False, t
ugc.commit()
return iddoc, 'ok'
def docmd_remove_comment(self, authenticator, myargs):
if not myargs:
return None, 'wrong arguments'
try:
iddoc = int(myargs[0])
except (ValueError,):
return False, 'not a valid iddoc'
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return False, 'no session data available'
ugc = self._load_ugc_interface()
iddoc_userid = ugc.get_iddoc_userid(iddoc)
if iddoc_userid == None:
return False, 'document not available'
# check if admin/mod or author
if authenticator.is_user() and (userid != iddoc_userid):
return False, 'permission denied'
ugc = self._load_ugc_interface()
status, iddoc = ugc.remove_comment(iddoc)
if not status:
return False, 'document not removed or not available'
ugc.commit()
return iddoc, 'ok'
def docmd_edit_comment(self, authenticator, myargs):
if len(myargs) < 2:
return None, 'wrong arguments'
try:
iddoc = int(myargs[0])
except (ValueError,):
return False, 'not a valid iddoc'
xml_string = ' '.join(myargs[1:])
try:
mydict = entropy.tools.dict_from_xml(xml_string)
except Exception as e:
return None, "error: %s" % (e,)
if not ('comment' in mydict and 'title' in mydict and 'keywords' in mydict):
return None, 'wrong dict arguments, xml must have two item with attr value -> comment, title'
new_comment = mydict.get('comment')
new_title = mydict.get('title')
new_keywords = mydict.get('keywords')
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return False, 'no session data available'
ugc = self._load_ugc_interface()
iddoc_userid = ugc.get_iddoc_userid(iddoc)
if iddoc_userid == None:
return False, 'document not available'
# check if admin/mod or author
if authenticator.is_user() and (userid != iddoc_userid):
return False, 'permission denied'
status, iddoc = ugc.edit_comment(iddoc, new_comment, new_title, new_keywords)
if not status:
return False, 'document not removed or not available'
ugc.commit()
return iddoc, 'ok'
def docmd_remove_image(self, authenticator, myargs):
if not myargs:
return None, 'wrong arguments'
try:
iddoc = int(myargs[0])
except (ValueError,):
return False, 'not a valid iddoc'
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return False, 'no session data available'
ugc = self._load_ugc_interface()
iddoc_userid = ugc.get_iddoc_userid(iddoc)
if iddoc_userid == None:
return False, 'document not available'
# check if admin/mod or author
if authenticator.is_user() and (userid != iddoc_userid):
return False, 'permission denied'
ugc = self._load_ugc_interface()
status, iddoc = ugc.delete_image(iddoc)
if not status:
return False, 'document not removed or not available'
ugc.commit()
return iddoc, 'ok'
def docmd_remove_file(self, authenticator, myargs):
if not myargs:
return None, 'wrong arguments'
try:
iddoc = int(myargs[0])
except (ValueError,):
return False, 'not a valid iddoc'
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return False, 'no session data available'
ugc = self._load_ugc_interface()
iddoc_userid = ugc.get_iddoc_userid(iddoc)
if iddoc_userid == None:
return False, 'document not available'
# check if admin/mod or author
if authenticator.is_user() and (userid != iddoc_userid):
return False, 'permission denied'
ugc = self._load_ugc_interface()
status, iddoc = ugc.delete_file(iddoc)
if not status:
return False, 'document not removed or not available'
ugc.commit()
return iddoc, 'ok'
def docmd_remove_youtube_video(self, authenticator, myargs):
if not myargs:
return None, 'wrong arguments'
try:
iddoc = int(myargs[0])
except (ValueError,):
return False, 'not a valid iddoc'
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return False, 'no session data available'
ugc = self._load_ugc_interface()
iddoc_userid = ugc.get_iddoc_userid(iddoc)
if iddoc_userid == None:
return False, 'document not available'
# check if admin/mod or author
if authenticator.is_user() and (userid != iddoc_userid):
return False, 'permission denied'
ugc = self._load_ugc_interface()
status, iddoc = ugc.remove_youtube_video(iddoc)
if not status:
return False, 'document not removed or not available'
ugc.commit()
return iddoc, 'ok'
def docmd_do_vote(self, authenticator, myargs):
if len(myargs) < 2:
return None, 'wrong arguments'
pkgkey = myargs[0]
vote = myargs[1]
userid = self._get_userid(authenticator)
if userid == None:
return False, 'no session userid available'
elif isinstance(userid, bool) and not userid:
return userid, 'no session data available'
ugc = self._load_ugc_interface()
voted = ugc.do_vote(pkgkey, userid, vote)
if not voted:
return voted, 'already voted'
ugc.commit()
return voted, 'ok'
def docmd_do_download_stats(self, authenticator, myargs):
if not myargs:
return None, 'wrong arguments'
xml_string = ' '.join(myargs)
try:
mydict = entropy.tools.dict_from_xml(xml_string)
except Exception as e:
return None, "error: %s" % (e,)
if not ('branch' in mydict and \
'release_string' in mydict and \
'pkgkeys' in mydict):
return None, 'wrong dict arguments, xml must have 3 items with attr value -> branch, release_string, pkgkeys'
branch = mydict.get('branch')
release_string = mydict.get('release_string')
hw_hash = mydict.get('hw_hash')
pkgkeys = mydict.get('pkgkeys').split()
ip_addr = self._get_session_ip_address(authenticator)
ugc = self._load_ugc_interface()
done = ugc.do_download_stats(branch, release_string, hw_hash, pkgkeys,
ip_addr)
if not done:
return done, 'stats not stored'
ugc.commit()
return done, 'ok'
def _get_generic_doctypes(self, pkgkey, doctypes):
ugc = self._load_ugc_interface()
metadata = ugc.get_ugc_metadata_doctypes(pkgkey, doctypes)
if not metadata:
return None
return metadata
def _get_generic_doctypes_by_identifiers(self, identifiers, doctypes):
ugc = self._load_ugc_interface()
metadata = ugc.get_ugc_metadata_doctypes_by_identifiers(identifiers, doctypes)
if not metadata:
return None
return metadata
def _get_generic_documents_by_identifiers(self, identifiers):
ugc = self._load_ugc_interface()
metadata = ugc.get_ugc_metadata_by_identifiers(identifiers)
if not metadata:
return None
return metadata
def docmd_get_comments(self, myargs):
if not myargs:
return None, 'wrong arguments'
pkgkey = myargs[0]
metadata = self._get_generic_doctypes(pkgkey, [self.DOC_TYPES['comments']])
if metadata == None:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_get_comments_by_identifiers(self, myargs):
if not myargs:
return None, 'wrong arguments'
identifiers = []
for myarg in myargs:
try:
identifiers.append(int(myarg))
except ValueError:
pass
if not identifiers:
return None, 'wrong arguments'
metadata = self._get_generic_doctypes_by_identifiers(identifiers, [self.DOC_TYPES['comments']])
if metadata == None:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_get_documents_by_identifiers(self, myargs):
if not myargs:
return None, 'wrong arguments'
identifiers = []
for myarg in myargs:
try:
identifiers.append(int(myarg))
except ValueError:
pass
if not identifiers:
return None, 'wrong arguments'
metadata = self._get_generic_documents_by_identifiers(identifiers)
if metadata == None:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_get_allvotes(self):
ugc = self._load_ugc_interface()
metadata = ugc.get_ugc_allvotes()
if not metadata:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_get_alldownloads(self):
ugc = self._load_ugc_interface()
metadata = ugc.get_ugc_alldownloads()
if not metadata:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_get_vote(self, myargs):
if not myargs:
return None, 'wrong arguments'
pkgkey = myargs[0]
ugc = self._load_ugc_interface()
vote = ugc.get_ugc_vote(pkgkey)
return vote, 'ok'
def docmd_get_downloads(self, myargs):
if not myargs:
return None, 'wrong arguments'
pkgkey = myargs[0]
ugc = self._load_ugc_interface()
downloads = ugc.get_ugc_downloads(pkgkey)
return downloads, 'ok'
def docmd_get_textdocs(self, myargs):
if not myargs:
return None, 'wrong arguments'
pkgkey = myargs[0]
metadata = self._get_generic_doctypes(pkgkey, [self.DOC_TYPES['comments'], self.DOC_TYPES['bbcode_doc']])
if metadata == None:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_get_textdocs_by_identifiers(self, myargs):
if not myargs:
return None, 'wrong arguments'
identifiers = []
for myarg in myargs:
try:
identifiers.append(int(myarg))
except ValueError:
pass
if not identifiers:
return None, 'wrong arguments'
metadata = self._get_generic_doctypes_by_identifiers(identifiers, [self.DOC_TYPES['comments'], self.DOC_TYPES['bbcode_doc']])
if metadata == None:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_get_alldocs(self, myargs):
if not myargs:
return None, 'wrong arguments'
pkgkey = myargs[0]
metadata = self._get_generic_doctypes(pkgkey, [self.DOC_TYPES[x] for x in self.DOC_TYPES])
if metadata == None:
return None, 'no metadata available'
return metadata, 'ok'
def docmd_do_report_error(self, authenticator, myargs):
if not myargs:
return None, 'wrong arguments'
import zlib
comp_xml_string = ' '.join(myargs)
try:
xml_string = zlib.decompress(comp_xml_string)
mydict = entropy.tools.dict_from_xml_extended(xml_string)
except Exception as e:
return None, "error: %s" % (e,)
subject = 'Entropy Error Reporting Handler'
sender_email = mydict.get('email', UGC.SENDER_EMAIL_FALLBACK)
if not entropy.tools.is_valid_email(sender_email):
sender_email = UGC.SENDER_EMAIL_FALLBACK
keys_to_file = ['errordata', 'processes', 'lspci', 'dmesg', 'locale',
'lsof', 'repositories.conf', 'client.conf']
# call it over
mail_txt = ''
for key in sorted(mydict):
if key in keys_to_file:
continue
mail_txt += '%s: %s\n' % (key, mydict.get(key),)
from datetime import datetime
import time
import tempfile
date = datetime.fromtimestamp(time.time())
# add ip address
ip_addr = self._get_session_ip_address(authenticator)
mail_txt += 'ip_address: %s\n' % (ip_addr,)
mail_txt += 'date: %s\n' % (date,)
files = []
rm_paths = []
for key in keys_to_file:
if key not in mydict:
continue
fd, path = tempfile.mkstemp(suffix = "__%s.txt" % (key,))
try:
with os.fdopen(fd, "w") as f_path:
f_path.write(mydict.get(key, ''))
f_path.flush()
except IOError:
continue
finally:
rm_paths.append(path)
files.append(path)
sender = EmailSender()
sender.send_mime_email(sender_email, [UGC.ERROR_REPORT_MAIL], subject,
mail_txt, files)
del sender
for rm_path in rm_paths:
os.remove(rm_path)
return True, 'ok'
File diff suppressed because it is too large Load Diff
@@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
cmd = 'test:echo %s' % ('c'*90000,)
from entropy.const import const_get_stringtype
from entropy.output import print_generic
from entropy.dump import unserialize_string
from entropy.client.interfaces import Client
from entropy.client.services.ugc.commands import Base
from entropy.services.ugc.interfaces import Client as SockClient
cl = Client()
srv = SockClient(cl, Base, ssl = True)
srv.connect('192.168.1.1', 2000)
session = srv.open_session()
srv.transmit('%s %s' % (session, cmd,))
print_generic("cmd answer", srv.receive())
srv.transmit('%s rc' % (session,))
raw_data = srv.receive()
if isinstance(raw_data, const_get_stringtype):
raw_data = unserialize_string(raw_data)
print_generic(raw_data)
srv.close_session(session)
srv.disconnect()
cl.destroy()
raise SystemExit(0)
@@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
import sys
from entropy.const import const_convert_to_unicode
from entropy.services.skel import RemoteDatabase
rd = RemoteDatabase()
action = "insert"
table = const_convert_to_unicode("òtableò", "utf-8")
data = {
'user': const_convert_to_unicode("Aleò", 'utf-8'),
'name': const_convert_to_unicode("Pippo", 'utf-8'),
}
sql = rd._generate_sql(action, table, data)
sys.stdout.write(sql.encode("utf-8") + "\n")
-169
View File
@@ -1,169 +0,0 @@
#!/usr/bin/python2
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Package Manager Service}.
"""
import os
import sys
import time
import signal
import threading
sys.path.insert(0,'/usr/lib/entropy/libraries')
sys.path.insert(0,'/usr/lib/entropy/client')
sys.path.insert(0,'../libraries')
sys.path.insert(0,'../client')
# disable pid management
sys.argv.append("--no-pid-handling")
do_ssl = False
do_stdout_logging = True
if "--ssl" in sys.argv:
do_ssl = True
if "--nostdout" in sys.argv:
do_stdout_logging = False
from entropy.i18n import _
from entropy.output import nocolor
from entropy.tools import get_year, print_traceback
from entropy.misc import ParallelTask
from entropy.core.settings.base import SystemSettings
from text_tools import print_menu
SysSettings = SystemSettings()
myopts = [
None,
(0," ~ "+SysSettings['system']['name']+" ~ "+sys.argv[0]+" ~ ",1,'Repository Services daemon - (C) %s' % (get_year(),) ),
None,
(0,_('Basic Options'),0,None),
None,
(1,'--help',2,_('this output')),
(1,'--nocolor',1,_('disable colorized output')),
None,
(0,_('Application Options'),0,None),
None,
(1,'--ssl',2,_('enable SSL service too')),
(1,'--nostdout',1,_('disable output to stdout, redirect to log file')),
None,
]
if "--nocolor" in sys.argv:
nocolor()
if "--help" in sys.argv:
print_menu(myopts)
raise SystemExit(1)
from entropy.services.repository.interfaces import Server
from entropy.services.auth_interfaces import phpBB3Auth as phpBB3AuthInterface
from entropy.services.authenticators import phpBB3
from entropy.services.commands import phpBB3 as phpBB3Commands
from entropy.services.ugc.commands import UGC
connection_data = {
'hostname': 'localhost',
'port': 3306,
'username': 'phpbb_user',
'password': 'mypassword',
'dbname': 'phpbb_db'
}
ugc_connection_data = {
'hostname': 'localhost',
'username': 'entropy',
'password': 'password',
'dbname': 'entropy',
'google_email': 'your@gmail.com', # valid google account
'google_password': 'yourgmailpassword', # valid google e-mail
'google_developer_key': 'xxxxx', # valid google developer key
'google_client_id': 'xxxx', # valid google client id connected to the developer key
}
ugc_store_path = "/path/to/your/ugc/store"
ugc_store_url = "http://www.yoursite.com"
ugc_args = [ugc_connection_data,ugc_store_path,ugc_store_url]
# configure my repositories
repositories = {
('sabayonlinux.org','amd64','standard','5',): {
'dbpath': '/repos/new.sabayonlinux.org/standard/amd64/5',
'cmethod': 'bz2',
},
}
def kill_threads():
for th in threading.enumerate():
if hasattr(th, 'kill'):
th.kill()
def term_myself():
os.kill(os.getpid(), signal.SIGTERM)
def run_srv(s):
try:
s.go()
except:
print_traceback()
raise
finally:
if s is not None:
s.killall()
kill_threads()
term_myself()
sock_auth = (phpBB3,[],connection_data)
srv_ssl = None
srv = Server(
do_ssl = False,
repositories = repositories,
stdout_logging = do_stdout_logging,
sock_auth = sock_auth,
external_cmd_classes = [phpBB3Commands,(UGC,ugc_args,)]
)
if do_ssl:
srv_ssl = Server(
do_ssl = True,
repositories = repositories,
stdout_logging = do_stdout_logging,
sock_auth = sock_auth,
external_cmd_classes = [phpBB3Commands,(UGC,ugc_args,)]
)
task = ParallelTask(run_srv, srv)
task.setName('repodaemon')
task.start()
task2 = None
if srv_ssl is not None:
task2 = ParallelTask(run_srv, srv_ssl)
task2.setName('repodaemon_ssl')
task2.start()
run_map = {
"repodaemon": srv,
}
if srv_ssl is not None:
run_map["repodaemon_ssl"] = srv_ssl
t_map = {
"repodaemon": task,
}
if task2 is not None:
t_map["repodaemon_ssl"] = task2
def threads_alive():
for th in t_map.values():
if th.isAlive():
return True
return False
try:
while threads_alive():
time.sleep(2)
finally:
for serv in run_map.values():
serv.killall()
kill_threads()
term_myself()
-1
View File
@@ -39,7 +39,6 @@ if "/usr/lib/entropy/sulfur" not in sys.path:
sys.path.insert(4, "/usr/lib/entropy/sulfur")
from entropy.exceptions import OnlineMirrorError, PermissionDenied
from entropy.services.exceptions import EntropyServicesError
import entropy.tools
from entropy.const import etpConst, const_get_stringtype, \
initconfig_entropy_constants, const_convert_to_unicode, \
-1
View File
@@ -28,7 +28,6 @@ import pango
from entropy.i18n import _, _LOCALE
from entropy.output import decolorize
from entropy.exceptions import *
from entropy.services.exceptions import TimeoutError
from entropy.const import *
from entropy.misc import ParallelTask
from entropy.services.client import WebService