def _mint_pid(obj, dummy_eng): d = Deposition(obj) recjson = d.get_latest_sip(sealed=False).metadata if 'recid' not in recjson: raise Exception("'recid' not found in sip metadata.") pid_text = None pid = recjson.get(pid_field, None) if not pid: # No pid found in recjson, so create new pid with user supplied # function. pid_text = recjson[pid_field] = pid_creator(recjson) else: # Pid found - check if it should be minted if existing_pid_checker and existing_pid_checker(pid, recjson): pid_text = pid # Create an assign pid internally - actually registration will happen # asynchronously later. if pid_text: current_app.logger.info("Registering pid %s" % pid_text) pid_obj = PersistentIdentifier.create(pid_store_type, pid_text) if pid_obj is None: pid_obj = PersistentIdentifier.get(pid_store_type, pid_text) try: pid_obj.assign("rec", recjson['recid']) except Exception: register_exception(alert_admin=True) d.update()
def __call__(self, environ, start_response): """Wrapper for legacy calls.""" with self.app.request_context(environ): g.start_response = start_response try: response = self.app.full_dispatch_request() except Exception as e: from invenio_ext.logging import register_exception register_exception(req=request, alert_admin=True) response = self.app.handle_exception(e) return response(environ, start_response)
def get_formatted_data(self, **kwargs): """Get the formatted representation for this object.""" from .registry import workflows try: name = self.get_workflow_name() if not name: return "Did not find any way to format data." workflow_definition = workflows[name] formatted_data = workflow_definition.formatter( self, **kwargs ) except (KeyError, AttributeError) as err: # Somehow the workflow or formatter does not exist from invenio_ext.logging import register_exception register_exception(alert_admin=True) formatted_data = "Error formatting record: {0}".format(err) return formatted_data
def get_formatted_data(self, of=None): """Get the formatted representation for this object.""" from .registry import workflows if of is None: of = cfg.get("WORKFLOWS_HOLDING_PEN_DEFAULT_OUTPUT_FORMAT") try: name = self.get_workflow_name() if not name: return "" workflow_definition = workflows[name] formatted_data = workflow_definition.formatter( self, of=of ) except (KeyError, AttributeError): # Somehow the workflow or formatter does not exist from invenio_ext.logging import register_exception register_exception(alert_admin=True) formatted_data = "" return formatted_data
def __call__(self, req, form): """Return deprecation warning.""" try: from invenio.legacy.webpage import page except ImportError: register_exception() def page(*args): return args[1] req.status = apache.HTTP_SERVICE_UNAVAILABLE msg = "<p>This functionality will be soon deprecated.</p>" try: from invenio.config import CFG_SITE_ADMIN_EMAIL msg += """<p>If you would still like to use it, please ask your Invenio administrator <code>%s</code> to consider enabling it. </p>""" % CFG_SITE_ADMIN_EMAIL except ImportError: pass try: return page('Service disabled', msg, req=req) except Exception: return msg
def __call__(self, req, form): try: from invenio.legacy.webpage import page except ImportError: register_exception() def page(*args): return args[1] req.status = apache.HTTP_SERVICE_UNAVAILABLE msg = ("<p>This functionality is currently unavailable due to " "a service maintenance.</p>") try: from invenio.config import CFG_SITE_ADMIN_EMAIL msg += ("<p>You can contact <code>%s</code> " "in case of questions.</p>" % CFG_SITE_ADMIN_EMAIL) except ImportError: pass msg += """<p>We are going to restore the service soon.</p> <p>Sorry for the inconvenience.</p>""" try: return page('Service unavailable', msg, req=req) except Exception: return msg
def calculate_RFC2104_HMAC(data, _amazon_secret_access_key): """ Computes a RFC 2104 compliant HMAC Signature and then Base64 encodes it. Module hashlib must be installed if Python < 2.5 <http://pypi.python.org/pypi/hashlib/20081119> @param data: data to sign @param _amazon_secret_access_key: your Amazon secret key @type data: string @type _amazon_secret_access_key: string. Empty if hashlib module not installed """ if not HASHLIB_IMPORTED: try: raise Exception( "Module hashlib not installed. Please install it.") except: from invenio_ext.logging import register_exception register_exception( stream='warning', alert_admin=True, subject='Cannot create AWS signature') return "" else: if sys.version_info < (2, 5): # compatibility mode for Python < 2.5 and hashlib my_digest_algo = _MySHA256(sha256()) else: my_digest_algo = sha256 return base64.encodestring( hmac.new( _amazon_secret_access_key, data, my_digest_algo).digest()).strip()
def acc_firerole_check_user(user_info, firerole_def_obj): """Matche the rules inside the deserialized compiled definition. Given a user_info dictionary, it matches the rules inside the deserialized compiled definition in order to discover if the current user match the roles corresponding to this definition. :param user_info: a dict produced by UserInfo(uid) which contains every info about a user :param firerole_def_obj: a compiled deserialized definition produced by compile_role_defintion :return: True if the user match the definition, False otherwise. """ try: default_allow_p, rules = firerole_def_obj # for every rule for (allow_p, not_p, field, expressions_list) in rules: group_p = field == 'group' # Is it related to group? ip_p = field == 'remote_ip' # Is it related to Ips? until_p = field == 'until' # Is it related to dates? from_p = field == 'from' # Idem. next_expr_p = False # Silly flag to break 2 for cycles if field not in user_info and not from_p and not until_p: continue # For every element in the rule for reg_p, expr in expressions_list: if group_p: # Special case: groups if reg_p: # When it is a regexp # iterate over every group for group in user_info[field]: if expr.match(group): # if it matches if not_p: # if must not match # let's skip to next expr next_expr_p = True break else: # Ok! return allow_p if next_expr_p: break # I said: let's skip to next rule ;-) # Simple expression then just check for expr in groups elif expr.lower() in [ group.lower() for group in user_info[field] ]: # If expr is in groups then if must not match if not_p: break # let's skip to next expr else: # Ok! return allow_p elif reg_p: # Not a group, then easier. If it's a regexp if expr.match(user_info[field]): # if it matches if not_p: # If must not match break # Let's skip to next expr else: return allow_p # Ok! # If it's just a simple expression but an IP! elif ip_p and isinstance(expr, tuple): # Then if Ip matches if _ipmatch(user_info['remote_ip'], expr): if not_p: # If must not match break # let's skip to next expr else: return allow_p # ok! elif until_p: if time.time() <= expr: if allow_p: break else: return False elif allow_p: return False else: break elif from_p: if time.time() >= expr: if allow_p: break else: return False elif allow_p: return False else: break # Finally the easiest one!! elif expr.lower() == str(user_info[field]).lower(): if not_p: # ... break else: # ... return allow_p # ... if not_p and not next_expr_p: # Nothing has matched and we got not return allow_p # Then the whole rule matched! except Exception as msg: register_exception(alert_admin=True) raise InvenioWebAccessFireroleError(msg) return default_allow_p # By default we allow ;-) it'an OpenAccess project
def create_Indico_request_url( base_url, indico_what, indico_loc, indico_id, indico_type, indico_params, indico_key, indico_sig, _timestamp=None): """ Create a signed Indico request URL to access Indico HTTP Export APIs. See U{http://indico.cern.ch/ihelp/html/ExportAPI/index.html} for more information. Example: >> create_Indico_request_url("https://indico.cern.ch", "categ", "", [1, 7], "xml", {'onlypublic': 'yes', 'order': 'title', 'from': 'today', 'to': 'tomorrow'}, '00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000000') @param base_url: Service base URL of the Indico instance to query @param indico_what: element to export @type indico_what: one of the strings: C{categ}, C{event}, C{room}, C{reservation} @param indico_loc: location of the element(s) specified by ID (only used for some elements) @param indico_id: ID of the element to be exported @type indico_id: a string or a list/tuple of strings @param indico_type: output format @type indico_type: one of the strings: C{json}, C{jsonp}, C{xml}, C{html}, C{ics}, C{atom} @param indico_params: parameters of the query. See U{http://indico.cern.ch/ihelp/html/ExportAPI/common.html} @param indico_key: API key provided for the given Indico instance @param indico_sig: API secret key (signature) provided for the given Indico instance @param _timestamp: for testing purpose only (default: current timestamp) @return signed URL of the request (string) """ url = '/export/' + indico_what + '/' if indico_loc: url += indico_loc + '/' if type(indico_id) in (list, tuple): # dash separated list of values indico_id = '-'.join([str(x) for x in indico_id]) url += indico_id + '.' + str(indico_type) if hasattr(indico_params, 'items'): items = indico_params.items() else: items = list(indico_params) if indico_key: items.append(('apikey', indico_key)) if indico_sig and HASHLIB_IMPORTED: if _timestamp: items.append(('timestamp', str(_timestamp))) else: items.append(('timestamp', str(int(time.time())))) items = sorted(items, key=lambda x: x[0].lower()) url_to_sign = '%s?%s' % (url, urlencode(items)) if sys.version_info < (2, 5): # compatibility mode for Python < 2.5 and hashlib my_digest_algo = _MySHA1(sha1()) else: my_digest_algo = sha1 signature = hmac.new(indico_sig, url_to_sign, my_digest_algo).hexdigest() items.append(('signature', signature)) elif not HASHLIB_IMPORTED: try: raise Exception("Module hashlib not installed. Please install it.") except: from invenio_ext.logging import register_exception register_exception(stream='warning', alert_admin=True, subject='Cannot create AWS signature') if not items: return url url = '%s%s?%s' % (base_url.strip('/'), url, urlencode(items)) return url
def main(): """Main function that analyzes command line input and calls whatever is appropriate. """ from invenio_access.firerole import repair_role_definitions from invenio_access.control import (acc_add_default_settings, acc_reset_default_settings) from invenio_base.globals import cfg DEF_DEMO_USER_ROLES = cfg.get('DEF_DEMO_USER_ROLES', tuple()) DEF_DEMO_ROLES = cfg.get('DEF_DEMO_ROLES', tuple()) DEF_DEMO_AUTHS = cfg.get('DEF_DEMO_AUTHS', tuple()) ## parse command line: # set user-defined options: options = {'user' : '', 'reset' : 0, 'compile' : 0, 'add' : 0, 'demo' : 0} try: opts, args = getopt.getopt(sys.argv[1:], "hVu:racD", ["help", "version", "user="******"reset", "add", "compile", "demo"]) except getopt.GetoptError as err: usage(1, err) try: for opt in opts: if opt[0] in ("-h", "--help"): usage(0) elif opt[0] in ("-V", "--version"): print(__revision__) sys.exit(0) elif opt[0] in ("-u", "--user"): options["user"] = opt[1] elif opt[0] in ("-r", "--reset"): options["reset"] = 1 elif opt[0] in ("-a", "--add"): options["add"] = 1 elif opt[0] in ("-c", "--compile"): options["compile"] = 1 elif opt[0] in ("-D", "--demo"): options["demo"] = 1 else: usage(1) if options['add'] or options['reset'] or options['compile']: #if acca.acc_get_action_id('cfgwebaccess'): # # Action exists hence authentication works :-) # options['user'] = authenticate(options['user'], # authorization_msg="WebAccess Administration", # authorization_action="cfgwebaccess") if options['reset'] and options['demo']: acc_reset_default_settings( [cfg['CFG_SITE_ADMIN_EMAIL']], DEF_DEMO_USER_ROLES, DEF_DEMO_ROLES, DEF_DEMO_AUTHS) print("Reset default demo site settings.") elif options['reset']: acc_reset_default_settings([cfg['CFG_SITE_ADMIN_EMAIL']]) print("Reset default settings.") elif options['add'] and options['demo']: acc_add_default_settings( [cfg['CFG_SITE_ADMIN_EMAIL']], DEF_DEMO_USER_ROLES, DEF_DEMO_ROLES, DEF_DEMO_AUTHS) print("Added default demo site settings.") elif options['add']: acc_add_default_settings([cfg['CFG_SITE_ADMIN_EMAIL']]) print("Added default settings.") if options['compile']: repair_role_definitions() print("Compiled firewall like role definitions.") else: usage(1, "You must specify at least one command") except StandardError as e: from invenio_ext.logging import register_exception register_exception() usage(e) return
def acc_firerole_check_user(user_info, firerole_def_obj): """Matche the rules inside the deserialized compiled definition. Given a user_info dictionary, it matches the rules inside the deserialized compiled definition in order to discover if the current user match the roles corresponding to this definition. :param user_info: a dict produced by UserInfo(uid) which contains every info about a user :param firerole_def_obj: a compiled deserialized definition produced by compile_role_defintion :return: True if the user match the definition, False otherwise. """ try: default_allow_p, rules = firerole_def_obj # for every rule for (allow_p, not_p, field, expressions_list) in rules: group_p = field == 'group' # Is it related to group? ip_p = field == 'remote_ip' # Is it related to Ips? until_p = field == 'until' # Is it related to dates? from_p = field == 'from' # Idem. next_expr_p = False # Silly flag to break 2 for cycles if field not in user_info and not from_p and not until_p: continue # For every element in the rule for reg_p, expr in expressions_list: if group_p: # Special case: groups if reg_p: # When it is a regexp # iterate over every group for group in user_info[field]: if expr.match(group): # if it matches if not_p: # if must not match # let's skip to next expr next_expr_p = True break else: # Ok! return allow_p if next_expr_p: break # I said: let's skip to next rule ;-) # Simple expression then just check for expr in groups elif expr.lower() in [group.lower() for group in user_info[field]]: # If expr is in groups then if must not match if not_p: break # let's skip to next expr else: # Ok! return allow_p elif reg_p: # Not a group, then easier. If it's a regexp if expr.match(user_info[field]): # if it matches if not_p: # If must not match break # Let's skip to next expr else: return allow_p # Ok! # If it's just a simple expression but an IP! elif ip_p and isinstance(expr, tuple): # Then if Ip matches if _ipmatch(user_info['remote_ip'], expr): if not_p: # If must not match break # let's skip to next expr else: return allow_p # ok! elif until_p: if time.time() <= expr: if allow_p: break else: return False elif allow_p: return False else: break elif from_p: if time.time() >= expr: if allow_p: break else: return False elif allow_p: return False else: break # Finally the easiest one!! elif expr.lower() == str(user_info[field]).lower(): if not_p: # ... break else: # ... return allow_p # ... if not_p and not next_expr_p: # Nothing has matched and we got not return allow_p # Then the whole rule matched! except Exception as msg: register_exception(alert_admin=True) raise InvenioWebAccessFireroleError(msg) return default_allow_p # By default we allow ;-) it'an OpenAccess project
def _handler(req): """ This handler is invoked by mod_python with the apache request.""" allowed_methods = ("GET", "POST", "HEAD", "OPTIONS", "PUT") #req.allow_methods(allowed_methods, 1) # if req.method not in allowed_methods: # raise apache.SERVER_RETURN, apache.HTTP_METHOD_NOT_ALLOWED if req.method == 'OPTIONS': # OPTIONS is used to now which method are allowed req.headers_out['Allow'] = ', '.join(allowed_methods) raise apache.SERVER_RETURN(apache.OK) # Set user agent for fckeditor.py, which needs it here os.environ["HTTP_USER_AGENT"] = req.headers_in.get('User-Agent', '') guest_p = int(current_user.is_guest) uri = req.uri if uri == '/': path = [''] else: # Let's collapse multiple slashes into a single / uri = RE_SLASHES.sub('/', uri) path = uri[1:].split('/') if CFG_ACCESS_CONTROL_LEVEL_SITE > 1: # If the site is under maintainance mode let's return # 503 to casual crawler to avoid having the site being # indexed req.status = 503 g = _RE_BAD_MSIE.search(req.headers_in.get('User-Agent', "MSIE 6.0")) bad_msie = g and float(g.group(1)) < 9.0 if uri.startswith('/yours') or not guest_p: # Private/personalized request should not be cached if bad_msie and req.is_https(): req.headers_out[ 'Cache-Control'] = 'private, max-age=0, must-revalidate' else: req.headers_out[ 'Cache-Control'] = 'private, no-cache, no-store, max-age=0, must-revalidate' req.headers_out['Pragma'] = 'no-cache' req.headers_out['Vary'] = '*' elif not (bad_msie and req.is_https()): req.headers_out['Cache-Control'] = 'public, max-age=3600' req.headers_out['Vary'] = 'Cookie, ETag, Cache-Control' try: if req.header_only and not RE_SPECIAL_URI.match(req.uri): return root._traverse(req, path, True, guest_p) else: # bibdocfile have a special treatment for HEAD return root._traverse(req, path, False, guest_p) except TraversalError: raise apache.SERVER_RETURN(apache.HTTP_NOT_FOUND) except apache.SERVER_RETURN: # This is one of mod_python way of communicating raise except IOError as exc: if 'Write failed, client closed connection' not in "%s" % exc: # Workaround for considering as false positive exceptions # rised by mod_python when the user close the connection # or in some other rare and not well identified cases. register_exception(req=req, alert_admin=True) raise except Exception: # send the error message, much more convenient than log hunting register_exception(req=req, alert_admin=True) raise # Serve an error by default. raise apache.SERVER_RETURN(apache.HTTP_NOT_FOUND)
def forge_email(fromaddr, toaddr, subject, content, html_content='', html_images=None, usebcc=False, header=None, footer=None, html_header=None, html_footer=None, ln=None, charset=None, replytoaddr="", attachments=None, bccaddr=""): """Prepare email. Add header and footer if needed. @param fromaddr: [string] sender @param toaddr: [string or list-of-strings] list of receivers (if string, then receivers are separated by ',') @param usebcc: [bool] True for using Bcc in place of To @param subject: [string] subject of the email @param content: [string] content of the email @param html_content: [string] html version of the email @param html_images: [dict] dictionary of image id, image path @param header: [string] None for the default header @param footer: [string] None for the default footer @param ln: language @charset: [string] the content charset. By default is None which means to try to encode the email as ascii, then latin1 then utf-8. @param replytoaddr: [string or list-of-strings] to be used for the reply-to header of the email (if string, then receivers are separated by ',') @param attachments: list of paths of files to be attached. Alternatively, every element of the list could be a tuple: (filename, mimetype) @param bccaddr: [string or list-of-strings] to be used for BCC header of the email (if string, then receivers are separated by ',') @return: forged email as an EmailMessage object""" from invenio_ext.template import render_template_to_string ln = default_ln(ln) if html_images is None: html_images = {} content = render_template_to_string( 'mail_text.tpl', content=unicodifier(content), header=unicodifier(header), footer=unicodifier(footer)).encode('utf8') if isinstance(toaddr, list): toaddr = ','.join(toaddr) if isinstance(bccaddr, list): bccaddr = ','.join(bccaddr) if isinstance(replytoaddr, list): replytoaddr = ','.join(replytoaddr) toaddr = remove_temporary_emails(toaddr) headers = {} kwargs = {'to': [], 'cc': [], 'bcc': []} if replytoaddr: headers['Reply-To'] = replytoaddr if usebcc: headers['Bcc'] = bccaddr kwargs['bcc'] = toaddr.split(',') + bccaddr.split(',') kwargs['to'] = ['Undisclosed.Recipients:'] else: kwargs['to'] = toaddr.split(',') headers['From'] = fromaddr headers['Date'] = formatdate(localtime=True) headers['User-Agent'] = 'Invenio %s at %s' % (cfg['CFG_VERSION'], cfg['CFG_SITE_URL']) if html_content: html_content = render_template_to_string( 'mail_html.tpl', content=unicodifier(html_content), header=unicodifier(html_header), footer=unicodifier(html_footer)).encode('utf8') msg_root = EmailMultiAlternatives(subject=subject, body=content, from_email=fromaddr, headers=headers, **kwargs) msg_root.attach_alternative(html_content, "text/html") # if not html_images: # # No image? Attach the HTML to the root # msg_root.attach(msg_text) # else: if html_images: # Image(s)? Attach the HTML and image(s) as children of a # "related" block msg_related = MIMEMultipart('related') # msg_related.attach(msg_text) for image_id, image_path in iteritems(html_images): attach_embed_image(msg_related, image_id, image_path) msg_root.attach(msg_related) else: msg_root = EmailMessage(subject=subject, body=content, from_email=fromaddr, headers=headers, **kwargs) if attachments: _mimes = MimeTypes(strict=False) for attachment in attachments: try: mime = None if type(attachment) in (list, tuple): attachment, mime = attachment if mime is None: # Automatic guessing of mimetype mime = _mimes.guess_type(attachment)[0] if mime is None: ext = _mimes.guess_extension(getContentType(attachment)) mime = _mimes.guess_type("foo" + ext)[0] if not mime: mime = 'application/octet-stream' part = MIMEBase(*mime.split('/', 1)) part.set_payload(open(attachment, 'rb').read()) Encoders.encode_base64(part) part.add_header( 'Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attachment)) msg_root.attach(part) except: from invenio_ext.logging import register_exception register_exception(alert_admin=True, prefix="Can't attach %s" % attachment) return msg_root
def send_email( fromaddr, toaddr, subject="", content="", html_content='', html_images=None, header=None, footer=None, html_header=None, html_footer=None, copy_to_admin=0, attempt_times=1, attempt_sleeptime=10, debug_level=0, ln=None, charset=None, replytoaddr="", attachments=None, bccaddr="", forward_failures_to_admin=True, ): """Send a forged email to TOADDR from FROMADDR with message created from subjet, content and possibly header and footer. @param fromaddr: [string] sender @param toaddr: [string or list-of-strings] list of receivers (if string, then receivers are separated by ','). BEWARE: If more than once receiptiant is given, the receivers are put in BCC and To will be "Undisclosed.Recipients:". @param subject: [string] subject of the email @param content: [string] content of the email @param html_content: [string] html version of the email @param html_images: [dict] dictionary of image id, image path @param header: [string] header to add, None for the Default @param footer: [string] footer to add, None for the Default @param html_header: [string] header to add to the html part, None for the Default @param html_footer: [string] footer to add to the html part, None for the Default @param copy_to_admin: [int] if 1 add CFG_SITE_ADMIN_EMAIL in receivers @param attempt_times: [int] number of tries @param attempt_sleeptime: [int] seconds in between tries @param debug_level: [int] debug level @param ln: [string] invenio language @param charset: [string] the content charset. By default is None which means to try to encode the email as ascii, then latin1 then utf-8. @param replytoaddr: [string or list-of-strings] to be used for the reply-to header of the email (if string, then receivers are separated by ',') @param attachments: list of paths of files to be attached. Alternatively, every element of the list could be a tuple: (filename, mimetype) @param bccaddr: [string or list-of-strings] to be used for BCC header of the email (if string, then receivers are separated by ',') @param forward_failures_to_admin: [bool] prevents infinite recursion in case of admin reporting, when the problem is not in the e-mail address format, but rather in the network If sending fails, try to send it ATTEMPT_TIMES, and wait for ATTEMPT_SLEEPTIME seconds in between tries. e.g.: send_email('*****@*****.**', '*****@*****.**', 'Let\'s try!'', 'check 1234', '<strong>check</strong> <em>1234</em><img src="cid:image1">', {'image1': '/tmp/quantum.jpg'}) @return: [bool]: True if email was sent okay, False if it was not. """ from invenio_ext.logging import register_exception ln = default_ln(ln) if html_images is None: html_images = {} if not isinstance(toaddr, list): toaddr = toaddr.strip().split(',') toaddr = remove_temporary_emails(toaddr) # More than one address, let's use Bcc in place of To usebcc = len(toaddr) > 1 if copy_to_admin: if cfg['CFG_SITE_ADMIN_EMAIL'] not in toaddr: toaddr.append(cfg['CFG_SITE_ADMIN_EMAIL']) if not isinstance(bccaddr, list): bccaddr = bccaddr.strip().split(',') msg = forge_email(fromaddr, toaddr, subject, content, html_content, html_images, usebcc, header, footer, html_header, html_footer, ln, charset, replytoaddr, attachments, bccaddr) if attempt_times < 1 or not toaddr: try: raise EmailError( _( 'The system is not attempting to send an email from %(x_from)s' ', to %(x_to)s, with body %(x_body)s.', x_from=fromaddr, x_to=toaddr, x_body=content)) except EmailError: register_exception() return False sent = False failure_reason = '' while not sent and attempt_times > 0: try: sent = msg.send() except Exception as e: failure_reason = str(e) register_exception() if debug_level > 1: try: raise EmailError( _('Error in sending message. \ Waiting %(sec)s seconds. Exception is %(exc)s, \ while sending email from %(sender)s to %(receipient)s \ with body %(email_body)s.', sec=attempt_sleeptime, exc=sys.exc_info()[0], sender=fromaddr, receipient=toaddr, email_body=content)) except EmailError: register_exception() if not sent: attempt_times -= 1 if attempt_times > 0: # sleep only if we shall retry again sleep(attempt_sleeptime) if not sent: # report failure to the admin with the intended message, its # sender and recipients if forward_failures_to_admin: # prepend '> ' to every line of the original message quoted_body = '> ' + '> '.join(content.splitlines(True)) # define and fill in the report template admin_report_subject = _( 'Error while sending an email: %(x_subject)s', x_subject=subject) admin_report_body = _( "\nError while sending an email.\n" "Reason: %(x_reason)s\n" "Sender: \"%(x_sender)s\"\n" "Recipient(s): \"%(x_recipient)s\"\n\n" "The content of the mail was as follows:\n" "%(x_body)s", x_reason=failure_reason, x_sender=fromaddr, x_recipient=', '.join(toaddr), x_body=quoted_body) send_email(cfg['CFG_SITE_ADMIN_EMAIL'], cfg['CFG_SITE_ADMIN_EMAIL'], admin_report_subject, admin_report_body, forward_failures_to_admin=False) try: raise EmailError( _( 'Error in sending email from %(x_from)s to %(x_to)s with body' '%(x_body)s.', x_from=fromaddr, x_to=toaddr, x_body=content)) except EmailError: register_exception() return sent
def send_email(fromaddr, toaddr, subject="", content="", html_content='', html_images=None, header=None, footer=None, html_header=None, html_footer=None, copy_to_admin=0, attempt_times=1, attempt_sleeptime=10, debug_level=0, ln=None, charset=None, replytoaddr="", attachments=None, bccaddr="", forward_failures_to_admin=True, ): """Send a forged email to TOADDR from FROMADDR with message created from subjet, content and possibly header and footer. @param fromaddr: [string] sender @param toaddr: [string or list-of-strings] list of receivers (if string, then receivers are separated by ','). BEWARE: If more than once receiptiant is given, the receivers are put in BCC and To will be "Undisclosed.Recipients:". @param subject: [string] subject of the email @param content: [string] content of the email @param html_content: [string] html version of the email @param html_images: [dict] dictionary of image id, image path @param header: [string] header to add, None for the Default @param footer: [string] footer to add, None for the Default @param html_header: [string] header to add to the html part, None for the Default @param html_footer: [string] footer to add to the html part, None for the Default @param copy_to_admin: [int] if 1 add CFG_SITE_ADMIN_EMAIL in receivers @param attempt_times: [int] number of tries @param attempt_sleeptime: [int] seconds in between tries @param debug_level: [int] debug level @param ln: [string] invenio language @param charset: [string] the content charset. By default is None which means to try to encode the email as ascii, then latin1 then utf-8. @param replytoaddr: [string or list-of-strings] to be used for the reply-to header of the email (if string, then receivers are separated by ',') @param attachments: list of paths of files to be attached. Alternatively, every element of the list could be a tuple: (filename, mimetype) @param bccaddr: [string or list-of-strings] to be used for BCC header of the email (if string, then receivers are separated by ',') @param forward_failures_to_admin: [bool] prevents infinite recursion in case of admin reporting, when the problem is not in the e-mail address format, but rather in the network If sending fails, try to send it ATTEMPT_TIMES, and wait for ATTEMPT_SLEEPTIME seconds in between tries. e.g.: send_email('*****@*****.**', '*****@*****.**', 'Let\'s try!'', 'check 1234', '<strong>check</strong> <em>1234</em><img src="cid:image1">', {'image1': '/tmp/quantum.jpg'}) @return: [bool]: True if email was sent okay, False if it was not. """ from invenio_ext.logging import register_exception ln = default_ln(ln) if html_images is None: html_images = {} if not isinstance(toaddr, list): toaddr = toaddr.strip().split(',') toaddr = remove_temporary_emails(toaddr) # More than one address, let's use Bcc in place of To usebcc = len(toaddr) > 1 if copy_to_admin: if cfg['CFG_SITE_ADMIN_EMAIL'] not in toaddr: toaddr.append(cfg['CFG_SITE_ADMIN_EMAIL']) if not isinstance(bccaddr, list): bccaddr = bccaddr.strip().split(',') msg = forge_email(fromaddr, toaddr, subject, content, html_content, html_images, usebcc, header, footer, html_header, html_footer, ln, charset, replytoaddr, attachments, bccaddr) if attempt_times < 1 or not toaddr: try: raise EmailError(_( 'The system is not attempting to send an email from %(x_from)s' ', to %(x_to)s, with body %(x_body)s.', x_from=fromaddr, x_to=toaddr, x_body=content)) except EmailError: register_exception() return False sent = False failure_reason = '' while not sent and attempt_times > 0: try: sent = msg.send() except Exception as e: failure_reason = str(e) register_exception() if debug_level > 1: try: raise EmailError(_('Error in sending message. \ Waiting %(sec)s seconds. Exception is %(exc)s, \ while sending email from %(sender)s to %(receipient)s \ with body %(email_body)s.', sec=attempt_sleeptime, exc=sys.exc_info()[0], sender=fromaddr, receipient=toaddr, email_body=content)) except EmailError: register_exception() if not sent: attempt_times -= 1 if attempt_times > 0: # sleep only if we shall retry again sleep(attempt_sleeptime) if not sent: # report failure to the admin with the intended message, its # sender and recipients if forward_failures_to_admin: # prepend '> ' to every line of the original message quoted_body = '> ' + '> '.join(content.splitlines(True)) # define and fill in the report template admin_report_subject = _( 'Error while sending an email: %(x_subject)s', x_subject=subject) admin_report_body = _( "\nError while sending an email.\n" "Reason: %(x_reason)s\n" "Sender: \"%(x_sender)s\"\n" "Recipient(s): \"%(x_recipient)s\"\n\n" "The content of the mail was as follows:\n" "%(x_body)s", x_reason=failure_reason, x_sender=fromaddr, x_recipient=', '.join(toaddr), x_body=quoted_body) send_email( cfg['CFG_SITE_ADMIN_EMAIL'], cfg['CFG_SITE_ADMIN_EMAIL'], admin_report_subject, admin_report_body, forward_failures_to_admin=False) try: raise EmailError(_( 'Error in sending email from %(x_from)s to %(x_to)s with body' '%(x_body)s.', x_from=fromaddr, x_to=toaddr, x_body=content)) except EmailError: register_exception() return sent
def forge_email(fromaddr, toaddr, subject, content, html_content='', html_images=None, usebcc=False, header=None, footer=None, html_header=None, html_footer=None, ln=None, charset=None, replytoaddr="", attachments=None, bccaddr=""): """Prepare email. Add header and footer if needed. @param fromaddr: [string] sender @param toaddr: [string or list-of-strings] list of receivers (if string, then receivers are separated by ',') @param usebcc: [bool] True for using Bcc in place of To @param subject: [string] subject of the email @param content: [string] content of the email @param html_content: [string] html version of the email @param html_images: [dict] dictionary of image id, image path @param header: [string] None for the default header @param footer: [string] None for the default footer @param ln: language @charset: [string] the content charset. By default is None which means to try to encode the email as ascii, then latin1 then utf-8. @param replytoaddr: [string or list-of-strings] to be used for the reply-to header of the email (if string, then receivers are separated by ',') @param attachments: list of paths of files to be attached. Alternatively, every element of the list could be a tuple: (filename, mimetype) @param bccaddr: [string or list-of-strings] to be used for BCC header of the email (if string, then receivers are separated by ',') @return: forged email as an EmailMessage object""" from invenio_ext.template import render_template_to_string ln = default_ln(ln) if html_images is None: html_images = {} content = render_template_to_string('mail_text.tpl', content=unicodifier(content), header=unicodifier(header), footer=unicodifier(footer) ).encode('utf8') if isinstance(toaddr, list): toaddr = ','.join(toaddr) if isinstance(bccaddr, list): bccaddr = ','.join(bccaddr) if isinstance(replytoaddr, list): replytoaddr = ','.join(replytoaddr) toaddr = remove_temporary_emails(toaddr) headers = {} kwargs = {'to': [], 'cc': [], 'bcc': []} if replytoaddr: headers['Reply-To'] = replytoaddr if usebcc: headers['Bcc'] = bccaddr kwargs['bcc'] = toaddr.split(',') + bccaddr.split(',') kwargs['to'] = ['Undisclosed.Recipients:'] else: kwargs['to'] = toaddr.split(',') headers['From'] = fromaddr headers['Date'] = formatdate(localtime=True) headers['User-Agent'] = 'Invenio %s at %s' % (cfg['CFG_VERSION'], cfg['CFG_SITE_URL']) if html_content: html_content = render_template_to_string( 'mail_html.tpl', content=unicodifier(html_content), header=unicodifier(html_header), footer=unicodifier(html_footer) ).encode('utf8') msg_root = EmailMultiAlternatives(subject=subject, body=content, from_email=fromaddr, headers=headers, **kwargs) msg_root.attach_alternative(html_content, "text/html") # if not html_images: # # No image? Attach the HTML to the root # msg_root.attach(msg_text) # else: if html_images: # Image(s)? Attach the HTML and image(s) as children of a # "related" block msg_related = MIMEMultipart('related') # msg_related.attach(msg_text) for image_id, image_path in iteritems(html_images): attach_embed_image(msg_related, image_id, image_path) msg_root.attach(msg_related) else: msg_root = EmailMessage(subject=subject, body=content, from_email=fromaddr, headers=headers, **kwargs) if attachments: _mimes = MimeTypes(strict=False) for attachment in attachments: try: mime = None if type(attachment) in (list, tuple): attachment, mime = attachment if mime is None: # Automatic guessing of mimetype mime = _mimes.guess_type(attachment)[0] if mime is None: ext = _mimes.guess_extension(getContentType(attachment)) mime = _mimes.guess_type("foo" + ext)[0] if not mime: mime = 'application/octet-stream' part = MIMEBase(*mime.split('/', 1)) part.set_payload(open(attachment, 'rb').read()) Encoders.encode_base64(part) part.add_header( 'Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attachment)) msg_root.attach(part) except: from invenio_ext.logging import register_exception register_exception( alert_admin=True, prefix="Can't attach %s" % attachment) return msg_root
def main(): """Main function that analyzes command line input and calls whatever is appropriate. """ from invenio_access.firerole import repair_role_definitions from invenio_access.control import (acc_add_default_settings, acc_reset_default_settings) from invenio_base.globals import cfg DEF_DEMO_USER_ROLES = cfg.get('DEF_DEMO_USER_ROLES', tuple()) DEF_DEMO_ROLES = cfg.get('DEF_DEMO_ROLES', tuple()) DEF_DEMO_AUTHS = cfg.get('DEF_DEMO_AUTHS', tuple()) ## parse command line: # set user-defined options: options = {'user': '', 'reset': 0, 'compile': 0, 'add': 0, 'demo': 0} try: opts, args = getopt.getopt( sys.argv[1:], "hVu:racD", ["help", "version", "user="******"reset", "add", "compile", "demo"]) except getopt.GetoptError as err: usage(1, err) try: for opt in opts: if opt[0] in ("-h", "--help"): usage(0) elif opt[0] in ("-V", "--version"): print(__revision__) sys.exit(0) elif opt[0] in ("-u", "--user"): options["user"] = opt[1] elif opt[0] in ("-r", "--reset"): options["reset"] = 1 elif opt[0] in ("-a", "--add"): options["add"] = 1 elif opt[0] in ("-c", "--compile"): options["compile"] = 1 elif opt[0] in ("-D", "--demo"): options["demo"] = 1 else: usage(1) if options['add'] or options['reset'] or options['compile']: #if acca.acc_get_action_id('cfgwebaccess'): # # Action exists hence authentication works :-) # options['user'] = authenticate(options['user'], # authorization_msg="WebAccess Administration", # authorization_action="cfgwebaccess") if options['reset'] and options['demo']: acc_reset_default_settings([cfg['CFG_SITE_ADMIN_EMAIL']], DEF_DEMO_USER_ROLES, DEF_DEMO_ROLES, DEF_DEMO_AUTHS) print("Reset default demo site settings.") elif options['reset']: acc_reset_default_settings([cfg['CFG_SITE_ADMIN_EMAIL']]) print("Reset default settings.") elif options['add'] and options['demo']: acc_add_default_settings([cfg['CFG_SITE_ADMIN_EMAIL']], DEF_DEMO_USER_ROLES, DEF_DEMO_ROLES, DEF_DEMO_AUTHS) print("Added default demo site settings.") elif options['add']: acc_add_default_settings([cfg['CFG_SITE_ADMIN_EMAIL']]) print("Added default settings.") if options['compile']: repair_role_definitions() print("Compiled firewall like role definitions.") else: usage(1, "You must specify at least one command") except StandardError as e: from invenio_ext.logging import register_exception register_exception() usage(e) return