def __repr__(self): r''' # note that we use raw strings to avoid having to use double back slashes below NOTE! This function is a clone of web2py:gluon.languages.utf_repl() function:: utf8.__repr__() works same as str.repr() when processing ascii string >>> repr(Utf8('abc')) == repr(Utf8("abc")) == repr('abc') == repr("abc") == "'abc'" True >>> repr(Utf8('a"b"c')) == repr('a"b"c') == '\'a"b"c\'' True >>> repr(Utf8("a'b'c")) == repr("a'b'c") == '"a\'b\'c"' True >>> repr(Utf8('a\'b"c')) == repr('a\'b"c') == repr(Utf8("a'b\"c")) == repr("a'b\"c") == '\'a\\\'b"c\'' True >>> repr(Utf8('a\r\nb')) == repr('a\r\nb') == "'a\\r\\nb'" # Test for \r, \n True Unlike str.repr(), Utf8.__repr__() remains utf8 content when processing utf8 string:: >>> repr(Utf8('中文字')) == repr(Utf8("中文字")) == "'中文字'" != repr('中文字') True >>> repr(Utf8('中"文"字')) == "'中\"文\"字'" != repr('中"文"字') True >>> repr(Utf8("中'文'字")) == '"中\'文\'字"' != repr("中'文'字") True >>> repr(Utf8('中\'文"字')) == repr(Utf8("中'文\"字")) == '\'中\\\'文"字\'' != repr('中\'文"字') == repr("中'文\"字") True >>> repr(Utf8('中\r\n文')) == "'中\\r\\n文'" != repr('中\r\n文') # Test for \r, \n True ''' if str.find(self, "'") >= 0 and str.find(self, '"') < 0: # only single quote exists return '"' + to_native(to_unicode(self, 'utf-8').translate(repr_escape_tab), 'utf-8') + '"' else: return "'" + to_native(to_unicode(self, 'utf-8').translate(repr_escape_tab2), 'utf-8') + "'"
def __new__(cls, content='', codepage='utf-8'): if isinstance(content, unicodeT): return str.__new__(cls, to_native(content, 'utf-8')) elif codepage in ('utf-8', 'utf8') or isinstance(content, cls): return str.__new__(cls, content) else: return str.__new__(cls, to_native(to_unicode(content, codepage), 'utf-8'))
def apply_filter(self, message, symbols={}, filter=None, ftag=None): def get_tr(message, prefix, filter): s = self.get_t(message, prefix) return filter(s) if filter else self.filter(s) if filter: prefix = '@' + (ftag or 'userdef') + '\x01' else: prefix = '@' + self.ftag + '\x01' message = get_from_cache( self.cache, prefix + message, lambda: get_tr(message, prefix, filter)) if symbols or symbols == 0 or symbols == "": if isinstance(symbols, dict): symbols.update( (key, xmlescape(value).translate(ttab_in)) for key, value in iteritems(symbols) if not isinstance(value, NUMBERS)) else: if not isinstance(symbols, tuple): symbols = (symbols,) symbols = tuple( value if isinstance(value, NUMBERS) else to_native(xmlescape(value)).translate(ttab_in) for value in symbols) message = self.params_substitution(message, symbols) return to_native(XML(message.translate(ttab_out)).xml())
def convert2html(book_id, text): extra = {} def url2(*a, **b): b['args'] = [book_id] + b.get('args', []) return URL(*a, **b) #def truncate(x): # return x[:70] + '...' if len(x) > 70 else x extra['verbatim'] = lambda code: to_native(cgi.escape(code)) extra['cite'] = lambda key: to_native( TAG.sup( '[', A(key, _href=URL('reference', args=(book_id, key)), _target='_blank'), ']').xml()) extra['inxx'] = lambda code: to_native('<div class="inxx">' + code + '</div>') extra['ref'] = lambda code: to_native('[ref:' + code + ']') # extra['code'] = lambda code: CODE(code, language='web2py').xml() try: from hladapter import hladapter except ImportError: redirect(URL('index', vars=dict(FLASH_MSG='ImportError'))) extra['code'] = hladapter # NOTE: pass id_prefix='' to preserve anchor names in urls, # is there any reason to have the insane 'markmin_' default value ? rtn = MARKMIN(text.replace('\r', ''), extra=extra, url=url2, id_prefix='') return rtn
def get_t(self, message, prefix=''): """ Use ## to add a comment into a translation string the comment can be useful do discriminate different possible translations for the same string (for example different locations): T(' hello world ') -> ' hello world ' T(' hello world ## token') -> ' hello world ' T('hello ## world## token') -> 'hello ## world' the ## notation is ignored in multiline strings and strings that start with ##. This is needed to allow markmin syntax to be translated """ message = to_native(message, 'utf8') prefix = to_native(prefix, 'utf8') key = prefix + message mt = self.t.get(key, None) if mt is not None: return mt # we did not find a translation if message.find('##') > 0: pass if message.find('##') > 0 and not '\n' in message: # remove comments message = message.rsplit('##', 1)[0] # guess translation same as original self.t[key] = mt = self.default_t.get(key, message) # update language file for latter translation if self.is_writable and is_writable() and \ self.language_file != self.default_language_file: write_dict(self.language_file, self.t) return regex_backslash.sub( lambda m: m.group(1).translate(ttab_in), to_native(mt))
def convert2html(book_id, text): extra = {} def url2(*a, **b): b['args'] = [book_id] + b.get('args', []) return URL(*a, **b) #def truncate(x): # return x[:70] + '...' if len(x) > 70 else x extra['verbatim'] = lambda code: to_native(cgi.escape(code)) extra['cite'] = lambda key: to_native(TAG.sup( '[', A(key, _href=URL('reference', args=(book_id, key)), _target='_blank'), ']').xml()) extra['inxx'] = lambda code: to_native('<div class="inxx">' + code + '</div>') extra['ref'] = lambda code: to_native('[ref:' + code + ']') # extra['code'] = lambda code: CODE(code, language='web2py').xml() try: from hladapter import hladapter except ImportError: redirect(URL('index', vars=dict(FLASH_MSG = 'ImportError'))) extra['code'] = hladapter # NOTE: pass id_prefix='' to preserve anchor names in urls, # is there any reason to have the insane 'markmin_' default value ? rtn = MARKMIN(text.replace('\r', ''), extra=extra, url=url2, id_prefix='') return rtn
def __new__(cls, content="", codepage="utf-8"): if isinstance(content, unicodeT): return str.__new__(cls, to_native(content, "utf-8")) elif codepage in ("utf-8", "utf8") or isinstance(content, cls): return str.__new__(cls, content) else: return str.__new__(cls, to_native(to_unicode(content, codepage), "utf-8"))
def include_meta(self): s = "\n" for meta in iteritems((self.meta or {})): k, v = meta if isinstance(v, dict): s += '<meta' + ''.join(' %s="%s"' % (xmlescape(key), to_native(xmlescape(v[key]))) for key in v) +' />\n' else: s += '<meta name="%s" content="%s" />\n' % (k, to_native(xmlescape(v))) self.write(s, escape=False)
def include_meta(self): s = "\n" for meta in iteritems((self.meta or {})): k, v = meta if isinstance(v, dict): s += '<meta' + ''.join(' %s="%s"' % (xmlescape(key), to_native(xmlescape(v[key]))) for key in v) + ' />\n' else: s += '<meta name="%s" content="%s" />\n' % (k, to_native(xmlescape(v))) self.write(s, escape=False)
def sub_tuple(m): """ word !word, !!word, !!!word ?word1?number ??number, ?number ?word1?number?word0 ?word1?number? ??number?word0 ??number? word[number] !word[number], !!word[number], !!!word[number] ?word1?word[number] ?word1?[number] ??word[number], ?word[number] ?word1?word?word0[number] ?word1?word?[number] ??word?word0[number] ??word?[number] """ w, i = m.group('w', 'i') c = w[0] if c not in '!?': return self.plural(w, symbols[int(i or 0)]) elif c == '?': (p1, sep, p2) = w[1:].partition("?") part1 = p1 if sep else "" (part2, sep, part3) = (p2 if sep else p1).partition("?") if not sep: part3 = part2 if i is None: # ?[word]?number[?number] or ?number if not part2: return m.group(0) num = int(part2) else: # ?[word1]?word[?word0][number] num = int(symbols[int(i or 0)]) return part1 if num == 1 else part3 if num == 0 else part2 elif w.startswith('!!!'): word = w[3:] fun = upper_fun elif w.startswith('!!'): word = w[2:] fun = title_fun else: word = w[1:] fun = cap_fun if i is not None: return to_native(fun(self.plural(word, symbols[int(i)]))) return to_native(fun(word))
def custom_json(o): if hasattr(o, 'custom_json') and callable(o.custom_json): return o.custom_json() if isinstance(o, (datetime.date, datetime.datetime, datetime.time)): return o.isoformat()[:19].replace('T', ' ') elif isinstance(o, (int, long)): return int(o) elif isinstance(o, decimal.Decimal): return str(o) elif isinstance(o, (bytes, bytearray)): return str(o) elif isinstance(o, lazyT): return str(o) elif isinstance(o, XmlComponent): return to_native(o.xml()) elif isinstance(o, set): return list(o) elif hasattr(o, 'as_list') and callable(o.as_list): return o.as_list() elif hasattr(o, 'as_dict') and callable(o.as_dict): return o.as_dict() else: raise TypeError(repr(o) + " is not JSON serializable")
def secure_loads_deprecated(data, encryption_key, hash_key=None, compression_level=None): encryption_key = to_bytes(encryption_key) data = to_native(data) if ':' not in data: return None if not hash_key: hash_key = sha1(encryption_key).hexdigest() signature, encrypted_data = data.split(':', 1) encrypted_data = to_bytes(encrypted_data) actual_signature = hmac.new(to_bytes(hash_key), encrypted_data, hashlib.md5).hexdigest() if not compare(signature, actual_signature): return None key = __pad_deprecated(encryption_key)[:32] encrypted_data = base64.urlsafe_b64decode(encrypted_data) IV, encrypted_data = encrypted_data[:16], encrypted_data[16:] cipher, _ = AES_new(key, IV=IV) try: data = AES_dec(cipher, encrypted_data) data = data.rstrip(b' ') if compression_level: data = zlib.decompress(data) return pickle.loads(data) except Exception as e: return None
def check_new_version(myversion, version_url): """Compares current web2py's version with the latest stable web2py version. Args: myversion: the current version as stored in file `web2py/VERSION` version_URL: the URL that contains the version of the latest stable release Returns: tuple: state, version - state : `True` if upgrade available, `False` if current version is up-to-date, -1 on error - version : the most up-to-version available """ try: version = to_native(urlopen(version_url).read()) pversion = parse_version(version) pmyversion = parse_version(myversion) except IOError: import traceback print(traceback.format_exc()) return -1, myversion if pversion[:3]+pversion[-6:] > pmyversion[:3]+pmyversion[-6:]: return True, version else: return False, version
def parse_post_vars(self): """Takes the body of the request and unpacks it into post_vars. application/json is also automatically parsed """ env = self.env post_vars = self._post_vars = Storage() body = self.body # if content-type is application/json, we must read the body is_json = env.get('content_type', '')[:16] == 'application/json' if is_json: try: # In Python 3 versions prior to 3.6 load doesn't accept bytes and # bytearray, so we read the body convert to native and use loads # instead of load. # This line can be simplified to json_vars = json_parser.load(body) # if and when we drop support for python versions under 3.6 json_vars = json_parser.loads(to_native(body.read())) except: # incoherent request bodies can still be parsed "ad-hoc" json_vars = {} pass # update vars and get_vars with what was posted as json if isinstance(json_vars, dict): post_vars.update(json_vars) body.seek(0) # parse POST variables on POST, PUT, BOTH only in post_vars if body and not is_json and env.request_method in ('POST', 'PUT', 'DELETE', 'BOTH'): query_string = env.pop('QUERY_STRING', None) dpost = cgi.FieldStorage(fp=body, environ=env, keep_blank_values=1) try: post_vars.update(dpost) except: pass if query_string is not None: env['QUERY_STRING'] = query_string # The same detection used by FieldStorage to detect multipart POSTs body.seek(0) def listify(a): return (not isinstance(a, list) and [a]) or a try: keys = sorted(dpost) except TypeError: keys = [] for key in keys: if key is None: continue # not sure why cgi.FieldStorage returns None key dpk = dpost[key] # if an element is not a file replace it with # its value else leave it alone pvalue = listify([(_dpk if _dpk.filename else _dpk.value) for _dpk in dpk] if isinstance(dpk, list) else (dpk if dpk.filename else dpk.value)) if len(pvalue): post_vars[key] = (len(pvalue) > 1 and pvalue) or pvalue[0]
def secure_loads(data, encryption_key, hash_key=None, compression_level=None): """loads a signed data dump""" data = to_bytes(data) components = data.count(b':') if components == 1: return secure_loads_deprecated(data, encryption_key, hash_key, compression_level) if components != 2: return None version, signature, encrypted_data = data.split(b':', 2) if version != b'hmac256': return None encryption_key = to_bytes(encryption_key) if not hash_key: hash_key = hashlib.sha256(encryption_key).digest() actual_signature = hmac.new(to_bytes(hash_key), encrypted_data, hashlib.sha256).hexdigest() if not compare(to_native(signature), actual_signature): return None encrypted_data = base64.urlsafe_b64decode(encrypted_data) IV, encrypted_data = encrypted_data[:16], encrypted_data[16:] cipher, _ = AES_new(pad(encryption_key)[:32], IV=IV) try: data = unpad(AES_dec(cipher, encrypted_data)) if compression_level: data = zlib.decompress(data) return pickle.loads(data) except Exception: return None
def secure_loads(data, encryption_key, hash_key=None, compression_level=None): data = to_bytes(data) components = data.count(b':') if components == 1: return secure_loads_deprecated(data, encryption_key, hash_key, compression_level) if components != 2: return None version, signature, encrypted_data = data.split(b':', 2) if version != b'hmac256': return None encryption_key = to_bytes(encryption_key) if not hash_key: hash_key = hashlib.sha256(encryption_key).digest() actual_signature = hmac.new(to_bytes(hash_key), encrypted_data, hashlib.sha256).hexdigest() if not compare(to_native(signature), actual_signature): return None encrypted_data = base64.urlsafe_b64decode(encrypted_data) IV, encrypted_data = encrypted_data[:16], encrypted_data[16:] cipher, _ = AES_new(pad(encryption_key)[:32], IV=IV) try: data = unpad(AES_dec(cipher, encrypted_data)) if compression_level: data = zlib.decompress(data) return pickle.loads(data) except Exception as e: return None
def check_new_version(myversion, version_url): """Compares current web2py's version with the latest stable web2py version. Args: myversion: the current version as stored in file `web2py/VERSION` version_URL: the URL that contains the version of the latest stable release Returns: tuple: state, version - state : `True` if upgrade available, `False` if current version is up-to-date, -1 on error - version : the most up-to-version available """ try: version = to_native(urlopen(version_url).read()) pversion = parse_version(version) pmyversion = parse_version(myversion) except IOError: import traceback print(traceback.format_exc()) return -1, myversion if pversion[:3] + pversion[-6:] > pmyversion[:3] + pmyversion[-6:]: return True, version else: return False, version
def parse_template(filename, path='views/', context=dict(), lexers={}, delimiters=('{{', '}}') ): """ Args: filename: can be a view filename in the views folder or an input stream path: is the path of a views folder context: is a dictionary of symbols used to render the template lexers: dict of custom lexers to use delimiters: opening and closing tags """ # First, if we have a str try to open the file if isinstance(filename, basestring): fname = os.path.join(path, filename) try: with open(fname, 'rb') as fp: text = fp.read() except IOError: raise RestrictedError(filename, '', 'Unable to find the file') else: text = filename.read() text = to_native(text) # Use the file contents to get a parsed template and return it. return str(TemplateParser(text, context=context, path=path, lexers=lexers, delimiters=delimiters))
def secure_loads_deprecated(data, encryption_key, hash_key=None, compression_level=None): """loads signed data (deprecated because of incorrect padding)""" encryption_key = to_bytes(encryption_key) data = to_native(data) if ':' not in data: return None if not hash_key: hash_key = hashlib.sha1(encryption_key).hexdigest() signature, encrypted_data = data.split(':', 1) encrypted_data = to_bytes(encrypted_data) actual_signature = hmac.new(to_bytes(hash_key), encrypted_data, hashlib.md5).hexdigest() if not compare(signature, actual_signature): return None key = __pad_deprecated(encryption_key)[:32] encrypted_data = base64.urlsafe_b64decode(encrypted_data) IV, encrypted_data = encrypted_data[:16], encrypted_data[16:] cipher, _ = AES_new(key, IV=IV) try: data = AES_dec(cipher, encrypted_data) data = data.rstrip(b' ') if compression_level: data = zlib.decompress(data) return pickle.loads(data) except Exception: return None
def custom_json(o): if hasattr(o, 'custom_json') and callable(o.custom_json): return o.custom_json() if isinstance(o, (datetime.date, datetime.datetime, datetime.time)): return o.isoformat()[:19].replace('T', ' ') elif isinstance(o, integer_types): return int(o) elif isinstance(o, decimal.Decimal): return str(o) elif isinstance(o, (bytes, bytearray)): return str(o) elif isinstance(o, lazyT): return str(o) elif isinstance(o, XmlComponent): return to_native(o.xml()) elif isinstance(o, set): return list(o) elif hasattr(o, 'as_list') and callable(o.as_list): return o.as_list() elif hasattr(o, 'as_dict') and callable(o.as_dict): return o.as_dict() else: raise TypeError(repr(o) + " is not JSON serializable")
def parse_template(filename, path='views/', context=dict(), lexers={}, delimiters=('{{', '}}')): """ Args: filename: can be a view filename in the views folder or an input stream path: is the path of a views folder context: is a dictionary of symbols used to render the template lexers: dict of custom lexers to use delimiters: opening and closing tags """ # First, if we have a str try to open the file if isinstance(filename, str): try: fp = open(os.path.join(path, filename), 'rb') text = fp.read() fp.close() except IOError: raise RestrictedError(filename, '', 'Unable to find the file') else: text = filename.read() text = to_native(text) # Use the file contents to get a parsed template and return it. return str( TemplateParser(text, context=context, path=path, lexers=lexers, delimiters=delimiters))
def read_dict_aux(filename): lang_text = open(filename, 'r').read().replace('\r\n', '\n') try: return safe_eval(to_native(lang_text)) or {} except Exception: e = sys.exc_info()[1] status = 'Syntax error in %s (%s)' % (filename, e) return {'__corrupted__': status}
def _CAS_login(self): """ exposed as CAS.login(request) returns a token on success, None on failed authentication """ self.ticket = current.request.vars.ticket if not current.request.vars.ticket: redirect("%s?service=%s" % (self.cas_login_url, self.cas_my_url)) else: url = "%s?service=%s&ticket=%s" % (self.cas_check_url, self.cas_my_url, self.ticket) data = to_native(urlopen(url).read()) if data.startswith('yes') or data.startswith('no'): data = data.split('\n') if data[0] == 'yes': if ':' in data[1]: # for Compatibility with Custom CAS items = data[1].split(':') a = items[0] b = len(items) > 1 and items[1] or a c = len(items) > 2 and items[2] or b else: a = b = c = data[1] return dict(user=a, email=b, username=c) return None try: dxml = dom.parseString(data) envelop = dxml.getElementsByTagName("cas:authenticationSuccess") if len(envelop) > 0: res = dict() for x in envelop[0].childNodes: if x.nodeName.startswith('cas:') and len(x.childNodes): key = to_native(x.nodeName[4:]) value = to_native(x.childNodes[0].nodeValue) if key not in res: res[key] = value else: if not isinstance(res[key], list): res[key] = [res[key]] res[key].append(value) return res except expat.ExpatError: pass return None # fallback
def _CAS_login(self): """ exposed as CAS.login(request) returns a token on success, None on failed authentication """ self.ticket = current.request.vars.ticket if not current.request.vars.ticket: redirect("%s?service=%s" % (self.cas_login_url, self.cas_my_url)) else: url = "%s?service=%s&ticket=%s" % (self.cas_check_url, self.cas_my_url, self.ticket) data = to_native(urlopen(url).read()) if data.startswith('yes') or data.startswith('no'): data = data.split('\n') if data[0] == 'yes': if ':' in data[1]: # for Compatibility with Custom CAS items = data[1].split(':') a = items[0] b = len(items) > 1 and items[1] or a c = len(items) > 2 and items[2] or b else: a = b = c = data[1] return dict(user=a, email=b, username=c) return None try: dxml = dom.parseString(data) envelop = dxml.getElementsByTagName( "cas:authenticationSuccess") if len(envelop) > 0: res = dict() for x in envelop[0].childNodes: if x.nodeName.startswith('cas:') and len(x.childNodes): key = to_native(x.nodeName[4:]) value = to_native(x.childNodes[0].nodeValue) if key not in res: res[key] = value else: if not isinstance(res[key], list): res[key] = [res[key]] res[key].append(value) return res except expat.ExpatError: pass return None # fallback
def read_dict_aux(filename): lang_text = read_locked(filename).replace(b'\r\n', b'\n') clear_cache(filename) try: return safe_eval(to_native(lang_text)) or {} except Exception: e = sys.exc_info()[1] status = 'Syntax error in %s (%s)' % (filename, e) logging.error(status) return {'__corrupted__': status}
def post(self): if hmac_key and not 'message' in self.request.arguments: self.send_error(401) if 'message' in self.request.arguments: message = self.request.arguments['message'][0] if hmac_key: signature = self.request.arguments['signature'][0] actual_signature = hmac.new(to_bytes(hmac_key), to_bytes(message), md5).hexdigest() if not gluon.utils.compare(to_native(signature), actual_signature): self.send_error(401) tokens[message] = None
def post(self): if hmac_key and not 'message' in self.request.arguments: self.send_error(401) if 'message' in self.request.arguments: message = self.request.arguments['message'][0] if hmac_key: signature = self.request.arguments['signature'][0] actual_signature = hmac.new(to_bytes(hmac_key), to_bytes(message)).hexdigest() if not gluon.utils.compare(to_native(signature), actual_signature): self.send_error(401) tokens[message] = None
def select(self): if self.op == 'eq' and self.field == 'id' and self.value: # means that someone wants to retrieve the key self.value key = self.keyprefix + ':' + str(self.value) if self.with_lock: acquire_lock(self.db.r_server, key + ':lock', self.value, 2) rtn = { to_native(k): v for k, v in self.db.r_server.hgetall(key).items() } if rtn: if self.unique_key: # make sure the id and unique_key are correct if rtn['unique_key'] == to_native(self.unique_key): rtn['update_record'] = self.update # update record support else: rtn = None return [Storage(self.db.convert_dict_string(rtn))] if rtn else [] elif self.op in ('ge', 'gt') and self.field == 'id' and self.value == 0: # means that someone wants the complete list rtn = [] id_idx = "%s:id_idx" % self.keyprefix # find all session keys of this app allkeys = self.db.r_server.smembers(id_idx) for sess in allkeys: val = self.db.r_server.hgetall(sess) if not val: if self.session_expiry: # clean up the idx, because the key expired self.db.r_server.srem(id_idx, sess) continue val = Storage(self.db.convert_dict_string(val)) # add a delete_record method (necessary for sessions2trash.py) val.delete_record = RecordDeleter(self.db, sess, self.keyprefix) rtn.append(val) return rtn else: raise Exception("Operation not supported")
def custom_importer(name, globals={}, locals=None, fromlist=(), level=_DEFAULT_LEVEL): """ web2py's custom importer. It behaves like the standard Python importer but it tries to transform import statements as something like "import applications.app_name.modules.x". If the import fails, it falls back on builtin importer. """ # support for non-ascii name if isinstance(name, unicodeT): name = to_native(name) if hasattr(current, 'request') \ and level <= 0 \ and name.partition('.')[0] not in INVALID_MODULES: # absolute import from application code try: return NATIVE_IMPORTER(name, globals, locals, fromlist, level) except (ImportError, KeyError): pass if current.request._custom_import_track_changes: base_importer = TRACK_IMPORTER else: base_importer = NATIVE_IMPORTER # rstrip for backward compatibility items = current.request.folder.rstrip(os.sep).split(os.sep) modules_prefix = '.'.join(items[-2:]) + '.modules' if not fromlist: # "import x" or "import x.y" result = None for itemname in name.split("."): new_mod = base_importer(modules_prefix, globals, locals, (itemname, ), level) modules_prefix += "." + itemname if result is None: try: result = sys.modules[modules_prefix] except KeyError: raise ImportError("No module named %s" % modules_prefix) return result else: # "from x import a, b, ..." pname = "%s.%s" % (modules_prefix, name) return base_importer(pname, globals, locals, fromlist, level) return NATIVE_IMPORTER(name, globals, locals, fromlist, level)
def contenttype(filename, default='text/plain'): """ Returns the Content-Type string matching extension of the given filename. """ filename = to_native(filename) i = filename.rfind('.') if i >= 0: default = CONTENT_TYPE.get(filename[i:].lower(), default) j = filename.rfind('.', 0, i) if j >= 0: default = CONTENT_TYPE.get(filename[j:].lower(), default) if default.startswith('text/'): default += '; charset=utf-8' return default
def post(self): if hmac_key and not 'signature' in self.request.arguments: self.send_error(401) if 'message' in self.request.arguments: message = self.request.arguments['message'][0].decode(encoding='UTF-8') group = self.request.arguments.get('group', ['default'])[0].decode(encoding='UTF-8') print('%s:MESSAGE to %s:%s' % (time.time(), group, message)) if hmac_key: signature = self.request.arguments['signature'][0] actual_signature = hmac.new(to_bytes(hmac_key), to_bytes(message), md5).hexdigest() if not gluon.utils.compare(to_native(signature), actual_signature): self.send_error(401) for client in listeners.get(group, []): client.write_message(message)
def post(self): if hmac_key and not 'signature' in self.request.arguments: self.send_error(401) if 'message' in self.request.arguments: message = self.request.arguments['message'][0].decode(encoding='UTF-8') group = self.request.arguments.get('group', ['default'])[0].decode(encoding='UTF-8') print('%s:MESSAGE to %s:%s' % (time.time(), group, message)) if hmac_key: signature = self.request.arguments['signature'][0] actual_signature = hmac.new(to_bytes(hmac_key), to_bytes(message)).hexdigest() if not gluon.utils.compare(to_native(signature), actual_signature): self.send_error(401) for client in listeners.get(group, []): client.write_message(message)
def findT(path, language=DEFAULT_LANGUAGE): """ Note: Must be run by the admin app """ from gluon.tools import Auth, Crud lang_file = pjoin(path, 'languages', language + '.py') sentences = read_dict(lang_file) mp = pjoin(path, 'models') cp = pjoin(path, 'controllers') vp = pjoin(path, 'views') mop = pjoin(path, 'modules') def add_message(message): if not message.startswith('#') and not '\n' in message: tokens = message.rsplit('##', 1) else: # this allows markmin syntax in translations tokens = [message] if len(tokens) == 2: message = tokens[0].strip() + '##' + tokens[1].strip() if message and not message in sentences: sentences[message] = message.replace("@markmin\x01", "") for filename in \ listdir(mp, '^.+\.py$', 0) + listdir(cp, '^.+\.py$', 0)\ + listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0): data = to_native(read_locked(filename)) items = regex_translate.findall(data) for x in regex_translate_m.findall(data): if x[0:3] in ["'''", '"""']: items.append("%s@markmin\x01%s" % (x[0:3], x[3:])) else: items.append("%s@markmin\x01%s" % (x[0], x[1:])) for item in items: try: message = safe_eval(item) except: continue # silently ignore inproperly formatted strings add_message(message) gluon_msg = [Auth.default_messages, Crud.default_messages] for item in [x for m in gluon_msg for x in m.values() if x is not None]: add_message(item) if not '!langcode!' in sentences: sentences['!langcode!'] = (DEFAULT_LANGUAGE if language in ('default', DEFAULT_LANGUAGE) else language) if not '!langname!' in sentences: sentences['!langname!'] = (DEFAULT_LANGUAGE_NAME if language in ( 'default', DEFAULT_LANGUAGE) else sentences['!langcode!']) write_dict(lang_file, sentences)
def findT(path, language=DEFAULT_LANGUAGE): """ Note: Must be run by the admin app """ from gluon.tools import Auth, Crud lang_file = pjoin(path, 'languages', language + '.py') sentences = read_dict(lang_file) mp = pjoin(path, 'models') cp = pjoin(path, 'controllers') vp = pjoin(path, 'views') mop = pjoin(path, 'modules') def add_message(message): if not message.startswith('#') and not '\n' in message: tokens = message.rsplit('##', 1) else: # this allows markmin syntax in translations tokens = [message] if len(tokens) == 2: message = tokens[0].strip() + '##' + tokens[1].strip() if message and not message in sentences: sentences[message] = message.replace("@markmin\x01", "") for filename in \ listdir(mp, '^.+\.py$', 0) + listdir(cp, '^.+\.py$', 0)\ + listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0): data = to_native(read_locked(filename)) items = regex_translate.findall(data) for x in regex_translate_m.findall(data): if x[0:3] in ["'''", '"""']: items.append("%s@markmin\x01%s" %(x[0:3], x[3:])) else: items.append("%s@markmin\x01%s" %(x[0], x[1:])) for item in items: try: message = safe_eval(item) except: continue # silently ignore inproperly formatted strings add_message(message) gluon_msg = [Auth.default_messages, Crud.default_messages] for item in [x for m in gluon_msg for x in m.values() if x is not None]: add_message(item) if not '!langcode!' in sentences: sentences['!langcode!'] = ( DEFAULT_LANGUAGE if language in ('default', DEFAULT_LANGUAGE) else language) if not '!langname!' in sentences: sentences['!langname!'] = ( DEFAULT_LANGUAGE_NAME if language in ('default', DEFAULT_LANGUAGE) else sentences['!langcode!']) write_dict(lang_file, sentences)
def custom_importer(name, globals={}, locals=None, fromlist=(), level=_DEFAULT_LEVEL): """ web2py's custom importer. It behaves like the standard Python importer but it tries to transform import statements as something like "import applications.app_name.modules.x". If the import fails, it falls back on builtin importer. """ # support for non-ascii name if isinstance(name, unicodeT): name = to_native(name) if hasattr(current, 'request') \ and level <= 0 \ and name.partition('.')[0] not in INVALID_MODULES: # absolute import from application code try: return NATIVE_IMPORTER(name, globals, locals, fromlist, level) except (ImportError, KeyError): pass if current.request._custom_import_track_changes: base_importer = TRACK_IMPORTER else: base_importer = NATIVE_IMPORTER # rstrip for backward compatibility items = current.request.folder.rstrip(os.sep).split(os.sep) modules_prefix = '.'.join(items[-2:]) + '.modules' if not fromlist: # "import x" or "import x.y" result = None for itemname in name.split("."): new_mod = base_importer( modules_prefix, globals, locals, (itemname,), level) modules_prefix += "." + itemname if result is None: try: result = sys.modules[modules_prefix] except KeyError: raise ImportError("No module named %s" % modules_prefix) return result else: # "from x import a, b, ..." pname = "%s.%s" % (modules_prefix, name) return base_importer(pname, globals, locals, fromlist, level) return NATIVE_IMPORTER(name, globals, locals, fromlist, level)
def simple_hash(text, key="", salt="", digest_alg="md5"): """Generate hash with the given text using the specified digest algorithm.""" text = to_bytes(text) key = to_bytes(key) salt = to_bytes(salt) if not digest_alg: raise RuntimeError("simple_hash with digest_alg=None") elif not isinstance(digest_alg, str): # manual approach h = digest_alg(text + key + salt) elif digest_alg.startswith("pbkdf2"): # latest and coolest! iterations, keylen, alg = digest_alg[7:-1].split(",") return to_native(pbkdf2_hex(text, salt, int(iterations), int(keylen), get_digest(alg))) elif key: # use hmac digest_alg = get_digest(digest_alg) h = hmac.new(key + salt, text, digest_alg) else: # compatible with third party systems h = get_digest(digest_alg)() h.update(text + salt) return h.hexdigest()
def simple_hash(text, key='', salt='', digest_alg='md5'): """Generate hash with the given text using the specified digest algorithm.""" text = to_bytes(text) key = to_bytes(key) salt = to_bytes(salt) if not digest_alg: raise RuntimeError("simple_hash with digest_alg=None") elif not isinstance(digest_alg, str): # manual approach h = digest_alg(text + key + salt) elif digest_alg.startswith('pbkdf2'): # latest and coolest! iterations, keylen, alg = digest_alg[7:-1].split(',') return to_native(pbkdf2_hex(text, salt, int(iterations), int(keylen), get_digest(alg))) elif key: # use hmac digest_alg = get_digest(digest_alg) h = hmac.new(key + salt, text, digest_alg) else: # compatible with third party systems h = get_digest(digest_alg)() h.update(text + salt) return h.hexdigest()
def _try_store_in_cookie(self, request, response): if self._forget or self._unchanged(response): # self.clear_session_cookies() self.save_session_id_cookie() return False name = response.session_data_name compression_level = response.session_cookie_compression_level value = secure_dumps(dict(self), current._session_cookie_key, compression_level=compression_level) rcookies = response.cookies rcookies.pop(name, None) rcookies[name] = to_native(value) rcookies[name]['path'] = '/' expires = response.session_cookie_expires if isinstance(expires, datetime.datetime): expires = expires.strftime(FMT) if expires: rcookies[name]['expires'] = expires return True
def check_new_version(myversion, version_url): """Compares current web2py's version with the latest stable web2py version. Args: myversion: the current version as stored in file `web2py/VERSION` version_URL: the URL that contains the version of the latest stable release Returns: tuple: state, version - state : `True` if upgrade available, `False` if current version is up-to-date, -1 on error, -2 when the system is likely to be offline (no internet link available) - version : the most up-to-version available """ try: version = to_native(urlopen(version_url).read()) pversion = parse_version(version) pmyversion = parse_version(myversion) except IOError as e: from socket import gaierror if isinstance(getattr(e, 'reason', None), gaierror) and \ e.reason.errno == -2: # assuming the version_url is ok the socket.gaierror # (gaierror stands for getaddrinfo() error) that # originates the exception is probably due to a # missing internet link (i.e. the system is offline) print('system is offline, cannot retrieve latest web2py version') return -2, myversion else: print(traceback.format_exc()) return -1, myversion if pversion[:3] + pversion[-6:] > pmyversion[:3] + pmyversion[-6:]: return True, version else: return False, version
def findT(path, language=DEFAULT_LANGUAGE): """ Note: Must be run by the admin app """ lang_file = pjoin(path, 'languages', language + '.py') sentences = read_dict(lang_file) mp = pjoin(path, 'models') cp = pjoin(path, 'controllers') vp = pjoin(path, 'views') mop = pjoin(path, 'modules') for filename in \ listdir(mp, '^.+\.py$', 0) + listdir(cp, '^.+\.py$', 0)\ + listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0): data = to_native(read_locked(filename)) items = regex_translate.findall(data) items += ["@markmin\x01%s" %x for x in regex_translate_m.findall(data)] for item in items: try: message = safe_eval(item) except: continue # silently ignore inproperly formatted strings if not message.startswith('#') and not '\n' in message: tokens = message.rsplit('##', 1) else: # this allows markmin syntax in translations tokens = [message] if len(tokens) == 2: message = tokens[0].strip() + '##' + tokens[1].strip() if message and not message in sentences: sentences[message] = message.replace("@markmin\x01", "") if not '!langcode!' in sentences: sentences['!langcode!'] = ( DEFAULT_LANGUAGE if language in ('default', DEFAULT_LANGUAGE) else language) if not '!langname!' in sentences: sentences['!langname!'] = ( DEFAULT_LANGUAGE_NAME if language in ('default', DEFAULT_LANGUAGE) else sentences['!langcode!']) write_dict(lang_file, sentences)
def findT(path, language=DEFAULT_LANGUAGE): """ Note: Must be run by the admin app """ lang_file = pjoin(path, 'languages', language + '.py') sentences = read_dict(lang_file) mp = pjoin(path, 'models') cp = pjoin(path, 'controllers') vp = pjoin(path, 'views') mop = pjoin(path, 'modules') for filename in \ listdir(mp, '^.+\.py$', 0) + listdir(cp, '^.+\.py$', 0)\ + listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0): data = to_native(read_locked(filename)) items = regex_translate.findall(data) items += regex_translate_m.findall(data) for item in items: try: message = safe_eval(item) except: continue # silently ignore inproperly formatted strings if not message.startswith('#') and not '\n' in message: tokens = message.rsplit('##', 1) else: # this allows markmin syntax in translations tokens = [message] if len(tokens) == 2: message = tokens[0].strip() + '##' + tokens[1].strip() if message and not message in sentences: sentences[message] = message if not '!langcode!' in sentences: sentences['!langcode!'] = (DEFAULT_LANGUAGE if language in ('default', DEFAULT_LANGUAGE) else language) if not '!langname!' in sentences: sentences['!langname!'] = (DEFAULT_LANGUAGE_NAME if language in ( 'default', DEFAULT_LANGUAGE) else sentences['!langcode!']) write_dict(lang_file, sentences)
def _get_file_text(self, filename): """ Attempts to open ``filename`` and retrieve its text. This will use self.path to search for the file. """ # If they didn't specify a filename, how can we find one! if not filename.strip(): self._raise_error('Invalid template filename') # Allow Views to include other views dynamically context = self.context if current and not "response" in context: context["response"] = getattr(current, 'response', None) # Get the filename; filename looks like ``"template.html"``. # We need to eval to remove the quotes and get the string type. filename = eval(filename, context) # Allow empty filename for conditional extend and include directives. if not filename: return '' # Get the path of the file on the system. filepath = self.path and os.path.join(self.path, filename) or filename # try to read the text. try: fileobj = open(filepath, 'rb') text = fileobj.read() fileobj.close() except IOError: self._raise_error('Unable to open included view file: ' + filepath) text = to_native(text) return text
def secure_loads(data, encryption_key, hash_key=None, compression_level=None): encryption_key = to_bytes(encryption_key) data = to_native(data) if ':' not in data: return None if not hash_key: hash_key = sha1(encryption_key).hexdigest() signature, encrypted_data = data.split(':', 1) encrypted_data = to_bytes(encrypted_data) actual_signature = hmac.new(to_bytes(hash_key), encrypted_data).hexdigest() if not compare(signature, actual_signature): return None key = pad(encryption_key)[:32] encrypted_data = base64.urlsafe_b64decode(encrypted_data) IV, encrypted_data = encrypted_data[:16], encrypted_data[16:] cipher, _ = AES_new(key, IV=IV) try: data = cipher.decrypt(encrypted_data) data = data.rstrip(b' ') if compression_level: data = zlib.decompress(data) return pickle.loads(data) except Exception as e: return None
def _get_file_text(self, filename): """ Attempts to open ``filename`` and retrieve its text. This will use self.path to search for the file. """ # If they didn't specify a filename, how can we find one! if not filename.strip(): self._raise_error('Invalid template filename') # Allow Views to include other views dynamically context = self.context if current and "response" not in context: context["response"] = getattr(current, 'response', None) # Get the filename; filename looks like ``"template.html"``. # We need to eval to remove the quotes and get the string type. filename = eval(filename, context) # Allow empty filename for conditional extend and include directives. if not filename: return '' # Get the path of the file on the system. filepath = self.path and os.path.join(self.path, filename) or filename # try to read the text. try: fileobj = open(filepath, 'rb') text = fileobj.read() fileobj.close() except IOError: self._raise_error('Unable to open included view file: ' + filepath) text = to_native(text) return text
def run_controller_in(controller, function, environment): """ Runs the controller.function() (for the app specified by the current folder). It tries pre-compiled controller.function.pyc first before compiling it. """ # if compiled should run compiled! folder = current.request.folder cpath = pjoin(folder, 'compiled') badc = 'invalid controller (%s/%s)' % (controller, function) badf = 'invalid function (%s/%s)' % (controller, function) if exists(cpath): filename = pjoin(cpath, 'controllers.%s.%s.pyc' % (controller, function)) try: ccode = getcfs(filename, filename, lambda: read_pyc(filename)) except IOError: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) elif function == '_TEST': # TESTING: adjust the path to include site packages paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '') [add_path_first(path) for path in paths] # TESTING END filename = pjoin(folder, 'controllers/%s.py' % controller) if not exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) environment['__symbols__'] = list(environment.keys()) code = read_file(filename) code += TEST_CODE ccode = compile2(code, filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) try: code = getcfs(filename, filename, lambda: read_file(filename)) except IOError: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) exposed = find_exposed_functions(code) if function not in exposed: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = "%s\nresponse._vars=response._caller(%s)" % (code, function) layer = "%s:%s" % (filename, function) ccode = getcfs(layer, filename, lambda: compile2(code, filename)) restricted(ccode, environment, layer=filename) response = environment["response"] vars = response._vars if response.postprocessing: vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars) if isinstance(vars, unicodeT): vars = to_native(vars) elif hasattr(vars, 'xml') and callable(vars.xml): vars = vars.xml() return vars
def write(self, data, escape=True): if not escape: self.body.write(str(data)) else: # FIXME PY3: self.body.write(to_native(xmlescape(data)))
def post(self, url, data=None, cookies=None, headers=None, auth=None, method='auto', charset='utf-8'): self.url = self.app + url # if this POST form requires a postback do it if data and '_formname' in data and self.postbacks and \ self.history and self.history[-1][1] != self.url: # to bypass the web2py CSRF need to get formkey # before submitting the form self.get(url, cookies=cookies, headers=headers, auth=auth) # unless cookies are specified, recycle cookies if cookies is None: cookies = self.cookies cookies = cookies or {} headers = headers or {} args = [ urllib2.HTTPCookieProcessor(self.cookiejar), urllib2.HTTPHandler(debuglevel=0) ] # if required do basic auth if auth: auth_handler = urllib2.HTTPBasicAuthHandler() auth_handler.add_password(**auth) args.append(auth_handler) opener = urllib2.build_opener(*args) # copy headers from dict to list of key,value headers_list = [] for key, value in iteritems(self.default_headers): if not key in headers: headers[key] = value for key, value in iteritems(headers): if isinstance(value, (list, tuple)): for v in value: headers_list.append((key, v)) else: headers_list.append((key, value)) # move cookies to headers for key, value in iteritems(cookies): headers_list.append(('Cookie', '%s=%s' % (key, value))) # add headers to request for key, value in headers_list: opener.addheaders.append((key, str(value))) # assume everything is ok and make http request error = None try: if isinstance(data, str): self.method = 'POST' if method == 'auto' else method elif isinstance(data, dict): self.method = 'POST' if method == 'auto' else method # if there is only one form, set _formname automatically if not '_formname' in data and len(self.forms) == 1: data['_formname'] = next(iter( self.forms.keys())) # Use the first key # if there is no formkey but it is known, set it if '_formname' in data and not '_formkey' in data and \ data['_formname'] in self.forms: data['_formkey'] = self.forms[data['_formname']] # time the POST request data = urlencode(data, doseq=True) else: self.method = 'GET' if method == 'auto' else method data = None t0 = time.time() self.response = opener.open(self.url, to_bytes(data)) self.time = time.time() - t0 except urllib2.HTTPError as er: error = er # catch HTTP errors self.time = time.time() - t0 self.response = er if hasattr(self.response, 'getcode'): self.status = self.response.getcode() else: #python2.5 self.status = None self.text = self.response.read() if charset: if charset == 'auto': charset = self.response.headers.getparam('charset') self.text = to_native(self.text, charset) # In PY3 self.response.headers are case sensitive self.headers = dict() for h in self.response.headers: self.headers[h.lower()] = self.response.headers[h] # treat web2py tickets as special types of errors if error is not None: if 'web2py_error' in self.headers: raise RuntimeError(self.headers['web2py_error']) else: raise error self._parse_headers_in_cookies() # check is a new session id has been issued, symptom of broken session if self.session_regex is not None: for cookie, value in iteritems(self.cookies): match = self.session_regex.match(cookie) if match: name = match.group('name') if name in self.sessions and self.sessions[name] != value: print(RuntimeError('Changed session ID %s' % name)) self.sessions[name] = value # find all forms and formkeys in page if charset: self.forms = {} for match in FORM_REGEX.finditer(self.text): self.forms[match.group('formname')] = match.group('formkey') # log this request self.history.append((self.method, self.url, self.status, self.time))
def run_controller_in(controller, function, environment): """ Runs the controller.function() (for the app specified by the current folder). It tries pre-compiled controller.function.pyc first before compiling it. """ # if compiled should run compiled! folder = current.request.folder cpath = pjoin(folder, 'compiled') badc = 'invalid controller (%s/%s)' % (controller, function) badf = 'invalid function (%s/%s)' % (controller, function) if os.path.exists(cpath): filename = pjoin(cpath, 'controllers.%s.%s.pyc' % (controller, function)) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) ccode = getcfs(filename, filename, lambda: read_pyc(filename)) elif function == '_TEST': # TESTING: adjust the path to include site packages from gluon.settings import global_settings from gluon.admin import abspath, add_path_first paths = (global_settings.gluon_parent, abspath( 'site-packages', gluon=True), abspath('gluon', gluon=True), '') [add_path_first(path) for path in paths] # TESTING END filename = pjoin(folder, 'controllers/%s.py' % controller) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) environment['__symbols__'] = environment.keys() code = read_file(filename) code += TEST_CODE ccode = compile2(code, filename) else: filename = pjoin(folder, 'controllers/%s.py' % controller) if not os.path.exists(filename): raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badc, web2py_error=badc) code = getcfs(filename, filename, lambda: read_file(filename)) exposed = find_exposed_functions(code) if not function in exposed: raise HTTP(404, rewrite.THREAD_LOCAL.routes.error_message % badf, web2py_error=badf) code = "%s\nresponse._vars=response._caller(%s)" % (code, function) layer = "%s:%s" % (filename, function) ccode = getcfs(layer, filename, lambda: compile2(code, filename)) restricted(ccode, environment, layer=filename) response = environment["response"] vars = response._vars if response.postprocessing: vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars) if isinstance(vars, unicodeT): vars = to_native(vars) elif hasattr(vars, 'xml') and callable(vars.xml): vars = vars.xml() return vars
def key_filter_out_windows(key): """ We need to decode the keys so regex based removal works. """ return to_native(base64.b32decode(to_bytes(key)))
def write(self, data, escape=True): if not escape: self.body.write(str(data)) else: self.body.write(to_native(xmlescape(data)))