Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:wrosenauer:devel
automx
automx-ox.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File automx-ox.patch of Package automx
diff --git a/src/automx/config.py b/src/automx/config.py index 1da4d3a..2ae555b 100644 --- a/src/automx/config.py +++ b/src/automx/config.py @@ -60,47 +60,47 @@ class Config(object, ConfigParser.RawConfigParser): independend from the view. It may query different backends to gather all required information needed to generate XML output later on in the view class. - + It uses a OrderdDict to guarentee the correct service order that is needed in the XML output. This said means that it is a difference, if a service like IMAP is configured before POP3 or upside down, because a MUA follows this order. - - The class currently support smtp, pop and imap services. - + + The class currently support smtp, pop, imap, carddav, caldav and ox services. + The class currently supports the following backends: - + -> global - This backend tells automx to use the global section - + -> static - all kind of service information that can be sent directly to the MUA - + -> filter - This backend can execute commands and collects results from stdout. The result may be "", which means we skip further searching. It may return data, which should point to a section that we try to follow. - + -> ldap - Read all kind of information from LDAP servers. The result attributes are stored in an internal dictionary and if options later on in this backend section (is read as static backend) do contain variables in the form ${attributename}, these are expanded to the collected data. - + -> sql - Read all kind of information from SQL servers. The result attributes are stored in an internal dictionary. See ldpa - + -> script - Execute a script and split a result into attributes, which are stored in an internal dictionary, See ldap - + -> file - Provide static files. If present, all collected data are discarded and only the static file is sent to the remote client. This may change in future releases. - + Note: There may exist a DEFAULT section that is appended to _all_ sections in the configuration file. That said you can do really complex configurations that on the other hand make life easier. This section also may contain variables, which, if found in the vars-dictionary, are used. - + """ def __init__(self, environ): ConfigParser.RawConfigParser.__init__(self, @@ -134,9 +134,9 @@ class Config(object, ConfigParser.RawConfigParser): self.debug = self.getboolean("automx", "debug") else: self.debug = False - + self.memcache = Memcache(self, environ) - + # defaults self.__emailaddress = "" self.__cn = "" @@ -149,27 +149,27 @@ class Config(object, ConfigParser.RawConfigParser): # if we use dynamic backends, we might earn variables self.__vars = dict() - + def configure(self, emailaddress, cn=None, password=None): if emailaddress is None: return OrderedDict() # Full email address containing local part _and_ domain self.__emailaddress = emailaddress - + # Mobileconfig if cn is not None: self.__cn = cn if password is not None: self.__password = password - + # The domain that is searched in the config file domain = emailaddress.split("@")[1] self.__search_domain = domain - + try: provider = self.get("automx", "provider") - + # provider must be a domainname pattern = "^[0-9a-zA-Z.-]+[a-zA-Z]{2,9}$" prog = re.compile(pattern) @@ -179,9 +179,9 @@ class Config(object, ConfigParser.RawConfigParser): else: logging.error("<provider> setting broken!") self.__automx["provider"] = "provider.broken" - + tmp = self.create_list(self.get("automx", "domains")) - self.__automx["domains"] = tmp + self.__automx["domains"] = tmp except TypeError: raise Exception("Missing options in section automx") @@ -205,16 +205,16 @@ class Config(object, ConfigParser.RawConfigParser): settings["domain"] = self.__search_domain settings["emailaddress"] = self.__emailaddress - + section = self.__find_section(section) - + if self.has_option(section, "backend"): if backend is None: try: backend = self.get(section, "backend") except NoOptionError: raise Exception("Missing option <backend>") - + if backend in ("static", "static_append"): for opt in iter(self.options(section)): if opt in ("action", @@ -234,6 +234,12 @@ class Config(object, ConfigParser.RawConfigParser): service = self.__service(section, "imap") elif opt == "pop": service = self.__service(section, "pop") + elif opt == "carddav": + service = self.__service(section, "carddav") + elif opt == "caldav": + service = self.__service(section, "caldav") + elif opt == "ox": + service = self.__service(section, "ox") elif opt == "sign_mobileconfig": try: settings[opt] = self.getboolean(section, opt) @@ -248,8 +254,8 @@ class Config(object, ConfigParser.RawConfigParser): logging.error("%s cannot read %s" % (opt, result)) else: pass - - if opt in ("smtp", "imap", "pop"): + + if opt in ("smtp", "imap", "pop", "caldav", "carddav", "ox"): if backend == "static_append": if settings.has_key(opt): if self.debug: @@ -321,12 +327,12 @@ class Config(object, ConfigParser.RawConfigParser): "key", "cacert"): result = self.get(section, opt) - + if opt in ("host", "result_attrs"): result = self.create_list(result) - + ldap_cfg[opt] = result - + # Do we connect with TLS? if ldap_cfg["usetls"].lower() in ("yes", "true", "1"): if ldap_cfg["reqcert"] in ("never", @@ -358,7 +364,7 @@ class Config(object, ConfigParser.RawConfigParser): ldap_cfg["key"]) tls = True - + # Are we SASL binding to our servers? if ldap_cfg["bindmethod"] == "sasl": mech = ldap_cfg["saslmech"] @@ -379,7 +385,7 @@ class Config(object, ConfigParser.RawConfigParser): auth_tokens = ldap.sasl.gssapi(ldap_cfg["authzid"]) sasl = True - + con = None for server in iter(ldap_cfg["host"]): @@ -406,12 +412,12 @@ class Config(object, ConfigParser.RawConfigParser): scope = ldap.SCOPE_BASE filter = self.__replace_makro(ldap_cfg["filter"]) - + rid = con.search(ldap_cfg["base"], scope, filter, ldap_cfg["result_attrs"]) - + raw_res = (None, None) raw_res = con.result(rid, True, 60) if raw_res[0] == None: @@ -420,7 +426,7 @@ class Config(object, ConfigParser.RawConfigParser): # connection established, we have results self.__vars = dict() - + # we did not receive data from LDAP if raw_res[1] != []: for entry in raw_res[1]: @@ -432,7 +438,7 @@ class Config(object, ConfigParser.RawConfigParser): logging.warning("No LDAP result from server!") raise DataNotFoundException - try: + try: con.unbind() except ldap.LDAPError, e: pass @@ -441,7 +447,7 @@ class Config(object, ConfigParser.RawConfigParser): self.__eval_options(section, backend="static") else: self.__eval_options(section, backend="static_append") - + elif backend in ("sql", "sql_append"): try: from sqlalchemy.engine import create_engine @@ -449,7 +455,7 @@ class Config(object, ConfigParser.RawConfigParser): raise Exception("python sqlalchemy missing") sql_cfg = dict(host = None, query = "", result_attrs = []) - + for opt in iter(self.options(section)): if opt in ("host", "result_attrs"): result = self.create_list(self.get(section, opt)) @@ -460,7 +466,7 @@ class Config(object, ConfigParser.RawConfigParser): sql_cfg["query"] = self.__replace_makro(query) else: raise Exception("Missing option <query>") - + for con in iter(sql_cfg["host"]): try: engine = create_engine(con) @@ -468,7 +474,7 @@ class Config(object, ConfigParser.RawConfigParser): except Exception, e: logging.error("SQL: %s" % e) continue - + result = connection.execute(sql_cfg["query"]) for row in result: keys = row.keys() @@ -484,7 +490,7 @@ class Config(object, ConfigParser.RawConfigParser): raise DataNotFoundException connection.close() - + break if backend == "sql": @@ -497,7 +503,7 @@ class Config(object, ConfigParser.RawConfigParser): if opt in ("autoconfig", "autodiscover", "mobileconfig"): tmp = self.get(section, opt) result = self.__expand_vars(tmp) - + if os.path.exists(result): settings[opt] = result @@ -564,32 +570,32 @@ class Config(object, ConfigParser.RawConfigParser): self.__eval_options(section, backend="static") else: self.__eval_options(section, backend="static_append") - + ### backends beyond this line do not have a follow option ### elif backend == "filter": if self.has_option(section, "section_filter"): tmp = self.create_list(self.get(section, "section_filter")) special_opts = tmp - + got_data = False - + for special_opt in iter(special_opts): if self.has_option(section, special_opt): - cmd = shlex.split(self.get(section, special_opt)) + cmd = shlex.split(self.get(section, special_opt)) for i, item in enumerate(cmd): cmd[i] = self.__replace_makro(item) stdout_fd = sys.__stdout__.fileno() - + pipe_in, pipe_out = os.pipe() - + pid = os.fork() if pid == 0: # child os.close(pipe_in) os.dup2(pipe_out, stdout_fd) - + os.execvp(cmd[0], cmd) raise Exception("ERROR in execvp()") @@ -597,11 +603,11 @@ class Config(object, ConfigParser.RawConfigParser): # parent os.close(pipe_out) recv = os.read(pipe_in, 1024) - + result = os.waitpid(pid, 0) else: continue - + # check return code if result[1] != 0: raise Exception("ERROR while calling filter", @@ -617,23 +623,23 @@ class Config(object, ConfigParser.RawConfigParser): if self.debug: logging.debug("Email address from filter: %s" % new_emailaddress) - + got_data = True - - # we replace our search_domain + + # we replace our search_domain self.__search_domain = special_opt self.__emailaddress = new_emailaddress # recurse again, because we now have a new section # that we need to scan self.__eval_options(special_opt) - + # we already got a result. Do not continue! break - + if not got_data: raise DataNotFoundException - + elif backend == "global": if self.has_section("global"): self.__eval_options("global") @@ -656,17 +662,17 @@ class Config(object, ConfigParser.RawConfigParser): result = self.__expand_vars(self.get(section, opt)) proto_settings[opt] = result - + if self.has_option(section, service + "_port"): opt = service + "_port" result = self.__expand_vars(self.get(section, opt)) - + proto_settings[opt] = result - + if self.has_option(section, service + "_encryption"): opt = service + "_encryption" result = self.__expand_vars(self.get(section, opt)) - + if result.lower() == "none": result = "none" elif result.lower() == "ssl": @@ -675,13 +681,13 @@ class Config(object, ConfigParser.RawConfigParser): result = "starttls" elif result.lower() == "auto": result = "auto" - + proto_settings[opt] = result - + if self.has_option(section, service + "_auth"): opt = service + "_auth" result = self.__expand_vars(self.get(section, opt)) - + if result.lower() == "plaintext": result = "cleartext" elif result.lower() == "encrypted": @@ -700,7 +706,7 @@ class Config(object, ConfigParser.RawConfigParser): if service == "smtp": result = "smtp-after-pop" # TODO: we allow bogus keys/values. - + proto_settings[opt] = result if self.has_option(section, service + "_auth_identity"): @@ -710,13 +716,13 @@ class Config(object, ConfigParser.RawConfigParser): else: emaillocalpart = self.__replace_makro("%u") proto_settings[service + "_auth_identity"] = emaillocalpart - + if self.has_option(section, service + "_expiration_date"): opt = service + "_expiration_date" result = self.__expand_vars(self.get(section, opt)) dt = parser.parse(result, fuzzy=True) proto_settings[opt] = dt.strftime("%Y%m%d") - + if self.has_option(section, service + "_refresh_ttl"): opt = service + "_refresh_ttl" result = self.get(section, opt) @@ -729,7 +735,7 @@ class Config(object, ConfigParser.RawConfigParser): if author == "%s": proto_settings[opt] = self.__emailaddress - + if self.has_option(section, service + "_default"): try: opt = service + "_default" @@ -743,16 +749,16 @@ class Config(object, ConfigParser.RawConfigParser): pass return proto_settings - + def create_list(self, value): result = value.split() - + if len(result) > 1: for i, item in enumerate(result): result[i] = item.split(",")[0] - + return result - + def __replace_makro(self, expression): if "%u" in expression: user = self.__emailaddress.split("@")[0] @@ -770,17 +776,17 @@ class Config(object, ConfigParser.RawConfigParser): # do we have some dynamic variables? if len(self.__vars) == 0: return expression - + def repl(mobj): if self.__vars.has_key(mobj.group(1)): result = self.__vars[mobj.group(1)] - + if mobj.group(2) is not None: macro = mobj.group(2)[1:] - + if self.debug: logging.debug("__expand_vars()->macro=%s" % macro) - + if "@" in result: if macro == "%u": return result.split("@")[0] @@ -788,9 +794,9 @@ class Config(object, ConfigParser.RawConfigParser): return result.split("@")[1] if macro == "%s": return result - + result = result.split("@")[1] - + # now the macro may only be part of a FQDN hostname if "." in result: dcs = result.split(".") @@ -799,9 +805,9 @@ class Config(object, ConfigParser.RawConfigParser): i = int(macro[1]) if len(dcs) < i: return "" - + return dcs[-i] - + return result else: # we always must expand variables. Even if it is the empty @@ -812,12 +818,12 @@ class Config(object, ConfigParser.RawConfigParser): repl, unicode(expression, "utf-8"), re.UNICODE) - + if self.debug: logging.debug("__expand_vars()->result=%s" % result) - + return result - + def __find_section(self, domain): l = self.sections() for section in iter(l): @@ -825,7 +831,7 @@ class Config(object, ConfigParser.RawConfigParser): return section raise NoSectionError(domain) - + def get_provider(self): return self.__automx["provider"] provider = property(fget=get_provider) @@ -841,25 +847,25 @@ class Config(object, ConfigParser.RawConfigParser): def get_password(self): return self.__password password = property(fget=get_password) - + def get_emailaddress(self): return self.__emailaddress emailaddress = property(fget=get_emailaddress) - - + + class Memcache(object): - + def __init__(self, config, environ): self.__config = config self.__environ = environ - + # Memcache usage is optional self.__has_memcache = use_memcache self.__found = False self.__client = None self.__current = 0 - + try: if use_memcache: self.__mc = memcache.Client([config.get("automx", "memcache")]) @@ -893,7 +899,7 @@ class Memcache(object): self.__current += 1 self.__mc.set(self.__client, self.__current, time=ttl) - + def allow_client(self): if not self.__has_memcache: return True @@ -907,7 +913,7 @@ class Memcache(object): else: if self.__config.debug: logging.debug("NOT TRUSTED %s" % self.__client) - + if self.__config.has_option("automx", "client_error_limit"): try: limit = self.__config.getint("automx", "client_error_limit") @@ -917,7 +923,7 @@ class Memcache(object): limit = 20 else: limit = 20 - + result = self.__mc.get(self.__client) if result is not None: @@ -937,7 +943,7 @@ class Memcache(object): networks = self.__config.create_list(networks) else: networks = ("127.0.0.1", "::1/128") - + for network in iter(networks): a = ipaddr.IPAddress(self.__client) n = ipaddr.IPNetwork(network) diff --git a/src/automx/view.py b/src/automx/view.py index 682c648..f792dae 100644 --- a/src/automx/view.py +++ b/src/automx/view.py @@ -26,7 +26,7 @@ import uuid import logging import M2Crypto import re - + from lxml import etree from lxml.etree import XMLSyntaxError from xml.parsers.expat import ExpatError @@ -40,19 +40,19 @@ class View(object): is used in Mozilla Thunderbird and several other open-source MUAs. It also supports .mobileconfig profile support as found on iOS devices. These profiles can also be used on Mac OS X Mail.app - + """ def __init__(self, model, schema, subschema): self.__model = model self.__schema = schema self.__subschema = subschema - + self.__xml = None self.__plist = None - + def __build_xml_plist_tree(self): root = None - + if self.__model.domain.has_key(self.__schema): if self.__schema in ("autodiscover", "autoconfig"): path = self.__model.domain[self.__schema] @@ -85,45 +85,45 @@ class View(object): response = etree.SubElement(root, "Response", xmlns=NS_Response) - + if (self.__model.domain.has_key("display_name") or (self.__model.domain.has_key("smtp") and self.__model.domain["smtp"][0].has_key("smtp_author"))): - + has_user = True - + user = etree.SubElement(response, "User") - + if self.__model.domain.has_key("display_name"): displayname = etree.SubElement(user, "DisplayName") displayname.text = self.__model.domain["display_name"] - + if self.__model.domain.has_key("smtp"): smtp = self.__model.domain["smtp"] - + if smtp[0].has_key("smtp_author"): email = smtp[0]["smtp_author"] - + smtp_author = etree.SubElement(user, "AutoDiscoverSMTPAddress") smtp_author.text = email - + account = etree.SubElement(response, "Account") - + if self.__model.domain.has_key("account_type"): account_type = etree.SubElement(account, "AccountType") account_type.text = self.__model.domain["account_type"] else: raise Exception("Missing attribute <account_type>") - + if self.__model.domain.has_key("action"): action = etree.SubElement(account, "Action") action.text = self.__model.domain["action"] else: raise Exception("Missing attribute <action>") - + for key, value in self.__model.domain.iteritems(): - if key in ("smtp", "imap", "pop"): + if key in ("smtp", "imap", "pop", "caldav", "carddav", "ox"): if len(value) != 0: protocol = etree.SubElement(account, "Protocol") self.__service(key, protocol) @@ -138,33 +138,33 @@ class View(object): response = etree.SubElement(root, "Response", xmlns=NS_Response) - + # TODO: do we need a Culture option? culture = etree.SubElement(response, "Culture") culture.text = "en:us" - + user = etree.SubElement(response, "User") - + if self.__model.domain.has_key("display_name"): displayname = etree.SubElement(user, "DisplayName") displayname.text = self.__model.domain["display_name"] - + emailaddress = etree.SubElement(user, "EmailAddress") emailaddress.text = self.__model.domain["emailaddress"] action = etree.SubElement(response, "Action") - + settings = etree.SubElement(action, "Settings") - + server = etree.SubElement(settings, "Server") - + servertype = etree.SubElement(server, "Type") servertype.text = "MobileSync" - + if self.__model.domain.has_key("server_url"): serverurl = etree.SubElement(server, "Url") serverurl.text = self.__model.domain["server_url"] - + if self.__model.domain.has_key("server_name"): servername = etree.SubElement(server, "Name") servername.text = self.__model.domain["server_name"] @@ -179,7 +179,7 @@ class View(object): elif self.__schema == "autoconfig": root = etree.Element("clientConfig", version="1.1") - + provider = etree.SubElement(root, "emailProvider", id=self.__model.provider) @@ -187,11 +187,11 @@ class View(object): domain = etree.SubElement(provider, "domain") if self.__model.domain.has_key("domain"): domain.text = self.__model.domain["domain"] - + display_name = etree.SubElement(provider, "displayName") if self.__model.domain.has_key("account_name"): display_name.text = self.__model.domain["account_name"] - + display_short = etree.SubElement(provider, "displayShortName") if self.__model.domain.has_key("account_name_short"): display_short.text = self.__model.domain["account_name_short"] @@ -200,7 +200,7 @@ class View(object): if key in ("smtp", "imap", "pop"): if len(value) != 0: self.__service(key, provider) - + self.__xml = root elif self.__schema == "mobileconfig": @@ -208,7 +208,7 @@ class View(object): # We only support IMAP or POP3. service_configured = False - + for key, value in self.__model.domain.iteritems(): if not service_configured and key == "imap": if len(value) != 0: @@ -223,12 +223,12 @@ class View(object): if key == "smtp": if len(value) != 0: self.__service(key, None, proto) - + if self.__model.domain.has_key("account_name"): org = self.__model.domain["account_name"] else: org = self.__model.provider - + email_account_name = self.__model.cn if self.__model.domain.has_key("display_name"): if self.__model.cn == "": @@ -239,10 +239,10 @@ class View(object): rev_email = self.__model.emailaddress.split("@") rev_email = ".".join(rev_email[::-1]) payload_identifier = ("org.automx.mail." - + rev_provider + + rev_provider + "." + rev_email) - + s = dict(EmailAccountDescription = org, EmailAccountName = email_account_name, EmailAccountType = proto["type"], @@ -269,7 +269,7 @@ class View(object): PreventAppSheet = False, PreventMove = False, SMIMEEnabled = False) - + self.__plist = dict(PayloadContent = [s], PayloadDescription = "Automx Email", PayloadDisplayName = org, @@ -287,14 +287,20 @@ class View(object): # we assume, autodiscover only supports single protocols! So we # only use the first defined list element elem = l[0] - + c = etree.SubElement(root, "Type") - + if service in ("smtp", "imap"): type = service.upper() elif service in "pop": type = "POP3" - + elif service in "caldav": + type = "CalDAV" + elif service in "carddav": + type = "CardDAV" + elif service in "ox": + type ="X-OX-APPSUITE" + c.text = type if elem.has_key(service + "_server"): @@ -305,7 +311,7 @@ class View(object): c = etree.SubElement(root, "Port") c.text = elem[service + "_port"] - + c = etree.SubElement(root, "DomainRequired") c.text = "off" # DomainName - not implemented, yet @@ -313,7 +319,7 @@ class View(object): if elem.has_key(service + "_auth_identity"): c = etree.SubElement(root, "LoginName") c.text = elem[service + "_auth_identity"] - + if elem.has_key(service + "_auth"): c = etree.SubElement(root, "SPA") @@ -324,7 +330,7 @@ class View(object): spa = "on" else: spa = "off" - + c.text = spa if elem.has_key(service + "_encryption"): @@ -343,7 +349,7 @@ class View(object): else: # anything that we can not understand leads into "None" ssl = "None" - + c.text = ssl c = etree.SubElement(root, "AuthRequired") @@ -380,32 +386,32 @@ class View(object): sub_root = etree.SubElement(root, "incomingServer", type="pop3") - + if elem.has_key(service + "_server"): c = etree.SubElement(sub_root, "hostname") c.text = elem[service + "_server"] - + if elem.has_key(service + "_port"): c = etree.SubElement(sub_root, "port") c.text = elem[service + "_port"] - + if elem.has_key(service + "_encryption"): c = etree.SubElement(sub_root, "socketType") - + value = elem[service + "_encryption"] - + if value in ("ssl", "starttls"): c.text = value.upper() elif value in ("none", "auto"): # autoconfig does not know anything about auto c.text = "plain" - + if elem.has_key(service + "_auth"): c = etree.SubElement(sub_root, "authentication") - + value = elem[service + "_auth"] result = "" - + if value == "cleartext": result = "password-cleartext" elif value == "encrypted": @@ -423,46 +429,46 @@ class View(object): elif value == "smtp-after-pop": if service == "smtp": result = "SMTP-after-POP" - + c.text = result - + if elem.has_key(service + "_auth_identity"): c = etree.SubElement(sub_root, "username") c.text = elem[service + "_auth_identity"] - + if service == "smtp": if elem.has_key(service + "_default"): value = elem[service + "_default"] - + c = etree.SubElement(sub_root, "useGlobalPreferredServer") c.text = value.lower() - + elif self.__schema == "mobileconfig": # see autodiscover comment above elem = l[0] - + if service == "imap": proto["type"] = "EmailTypeIMAP" if service == "pop": proto["type"] = "EmailTypePOP" - + if elem.has_key(service + "_server"): if service in ("imap", "pop"): proto["in_server"] = elem[service + "_server"] - else: + elif service == "smtp": proto["out_server"] = elem[service + "_server"] if elem.has_key(service + "_port"): if service in ("imap", "pop"): proto["in_port"] = int(elem[service + "_port"]) - else: + elif service == "smtp": proto["out_port"] = int(elem[service + "_port"]) - + if elem.has_key(service + "_auth_identity"): if service in ("imap", "pop"): proto["in_username"] = elem[service + "_auth_identity"] - else: + elif service == "smtp": proto["out_username"] = elem[service + "_auth_identity"] if elem.has_key(service + "_auth"): @@ -487,26 +493,26 @@ class View(object): pass elif value == "none": result = "EmailAuthNone" - + if service in ("imap", "pop"): proto["in_auth"] = result - else: + elif service == "smtp": proto["out_auth"] = result - + if elem.has_key(service + "_encryption"): value = elem[service + "_encryption"] - + if value in ("ssl", "starttls"): if service in ("imap", "pop"): proto["in_encryption"] = True - else: + elif service == "smtp": proto["out_encryption"] = True else: if service in ("imap", "pop"): proto["in_encryption"] = False - else: + elif service == "smtp": proto["out_encryption"] = False - + def render(self): """Return the XML result of the view as a character string. """ @@ -518,10 +524,10 @@ class View(object): method="xml", encoding="utf-8", pretty_print=True) - + elif self.__plist is not None: plist_unsigned = writePlistToString(self.__plist) - + if self.__model.domain.has_key("sign_mobileconfig"): if (self.__model.domain["sign_mobileconfig"] is True and self.__model.domain.has_key("sign_cert") and @@ -529,23 +535,23 @@ class View(object): sign_cert = self.__model.domain["sign_cert"] sign_key = self.__model.domain["sign_key"] - + buffer = M2Crypto.BIO.MemoryBuffer(plist_unsigned) signer = M2Crypto.SMIME.SMIME() s = M2Crypto.X509.X509_Stack() - + cert_handle = open(sign_cert).read() certificates = re.finditer(r"-----BEGIN CERTIFICATE-----" ".*?-----END CERTIFICATE-----", cert_handle, re.S) - + # First certificate is for signing! # Rest is intermediate cert chain! certificates.next() for match in certificates: s.push(M2Crypto.X509.load_cert_string(match.group(0))) signer.set_x509_stack(s) - + # Load key and _first_ certificate try: signer.load_key(sign_key, sign_cert) @@ -553,16 +559,16 @@ class View(object): logging.error("Cannot access %s or %s. Not signing!" % (sign_cert, sign_key)) return plist_unsigned - + p7 = signer.sign(buffer) output = M2Crypto.BIO.MemoryBuffer() p7.write_der(output) plist_signed = output.getvalue() - + return plist_signed else: logging.info("Not signing!") - + return plist_unsigned else: return ""
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor