def process_value(self, value, property, prefix=""): unique = property.get('unique', True) expected_type = property.expected_type.key at = {"key": self.key, "property": prefix + property.name} if isinstance(value, list): if unique is True: raise common.BadData(message='expected atom, found list', at=at, value=value) p = web.storage(property.copy()) p.unique = True return [self.process_value(v, p) for v in value] if unique is False: raise common.BadData(message='expected list, found atom', at=at, value=value) type_found = common.find_type(value) if expected_type in common.primitive_types: # string can be converted to any type and int can be converted to float try: if type_found == '/type/string' and expected_type != '/type/string': value = common.primitive_types[expected_type](value) elif type_found == '/type/int' and expected_type == '/type/float': value = float(value) except ValueError, e: raise common.BadData(message=str(e), at=at, value=value)
def get_user_email(self, username): logger.debug("get_user_email", username) if username.startswith("/"): # this is user key userkey = username username = username.split("/")[-1] else: userkey = get_user_root() + username details = self.site.store.get_user_details(username) logger.debug("get_user_email details %s %s", username, details) if details: return details.email doc = self.site.store.store.get("account/" + username) logger.debug("get_user_email doc %s", doc) if doc and doc.get("type") == "pending-account": return doc['email'] raise common.BadData(message='No user registered with username: ' + username, error="account_not_found")
def check_reset_code(self, username, code): SEC_PER_WEEK = 7 * 24 * 3600 timestamp, code = code.split('$', 1) # code is valid only for a week if int(timestamp) + SEC_PER_WEEK < int(time.time()): raise common.BadData(message='Password Reset code expired') username = get_user_root() + username details = self.site.store.get_user_details(username) if not details: raise common.BadData(message="Invalid username") text = details.password + '$' + timestamp if not self._check_salted_hash(self.secret_key, text, code): raise common.BadData(message="Invaid password reset code")
def register1(self, username, email, enc_password, data, ip=None, timestamp=None): ip = ip or web.ctx.ip key = get_user_root() + username if self.site.get(key): raise common.BadData(message="User already exists: " + username) if self.site.store.find_user(email): raise common.BadData(message='Email is already used: ' + email) def f(): web.ctx.disable_permission_check = True d = web.storage({"key": key, "type": {"key": "/type/user"}}) d.update(data) self.site.save(key, d, timestamp=timestamp, author=d, comment="Created new account") q = make_query(d) account_bot = config.get('account_bot') account_bot = account_bot and web.storage({"key": account_bot, "type": {"key": "/type/user"}}) self.site.save_many(q, ip=ip, timestamp=timestamp, author=account_bot, action='register', comment="Setup new account") self.site.store.register(key, email, enc_password) self.update_user_details(username, verified=True, active=True) # Add account doc to store olddoc = self.site.store.store.get("account/" + username) or {} doc = { "_key": "account/" + username, "_rev": olddoc.get("_rev"), "type": "account", "registered_on": olddoc['registered_on'], "activated_on": timestamp.isoformat(), "last_login": timestamp.isoformat(), } self.site.store.store.put("account/" + username, doc) timestamp = timestamp or datetime.datetime.utcnow() self.site.store.transact(f) event_data = dict(data, username=username, email=email, password=enc_password) self.site._fire_event("register", timestamp=timestamp, ip=ip or web.ctx.ip, username=None, data=event_data) self.set_auth_token(key) return username
def POST_activate(self, site): i = input('username') a = site.get_account_manager() status = a.activate(i.username) if status == "ok": return {"ok": "true"} else: raise common.BadData(error_code=status, message="Account activation failed.")
def POST_login(self, site): i = input('username', 'password') a = site.get_account_manager() status = a.login(i.username, i.password) if status == "ok": a.set_auth_token(get_user_root() + i.username) return {"ok": True} else: raise common.BadData(code=status, message="Login failed")
def input(*required, **defaults): if 'infobase_input' in web.ctx: d = web.ctx.infobase_input else: d = web.input() for k in required: if k not in d: raise common.BadData(message="Missing argument: " + repr(k)) result = web.storage(defaults) result.update(d) return result
def update_user(self, old_password, new_password, email): user = self.get_user() if user is None: raise common.PermissionDenied(message="Not logged in") if not self.checkpassword(user.key, old_password): raise common.BadData(message='Invalid Password') new_password and self.assert_password(new_password) email and self.assert_email(email) enc_password = new_password and self._generate_salted_hash(self.secret_key, new_password) self.update_user1(user, enc_password, email)
def store_account_info(self, username, email, enc_password, data): """Store account info in the store so that the account can be created after verifying the email. """ store = self.site.store.store email = email.strip() account_key = "account/" + username email_key = "account-email/" + email.lower() if store.get(account_key): raise common.BadData(message="User already exists: %s" % username) if store.get(email_key): raise common.BadData(message='Email is already used: ' + email) now = datetime.datetime.utcnow() expires_on = now + datetime.timedelta(days=14) # 2 weeks account_doc = { "_key": account_key, "type": "account", "status": "pending", "created_on": now.isoformat(), "username": username, "lusername": username.lower(), # lowercase username "email": email, "enc_password": enc_password, "data": data } email_doc = { "_key": email_key, "type": "account-email", "username": username } store.put_many([account_doc, email_doc])
def POST_update_user(self, site): i = input('old_password', new_password=None, email=None) a = site.get_account_manager() user = a.get_user() username = user.key.split("/")[-1] status = a.login(username, i.old_password) if status == "ok": kw = {} if i.new_password: kw['password'] = i.new_password if i.email: kw['email'] = i.email a.update(username, **kw) else: raise common.BadData(code=status, message="Invalid password")
def _process(self, key, data, prev_data=None): self.key = key # hack to make key available when raising exceptions. if 'key' not in data: data['key'] = key if web.ctx.get('infobase_bootstrap', False): return data assert data['key'] == key data = common.parse_query(data) self.validate_properties(data) prev_data = prev_data and common.parse_query(prev_data) if not web.ctx.get('disable_permission_check', False) and not self.has_permission(self.author, key): raise common.PermissionDenied(message='Permission denied to modify %s' % repr(key)) type = data.get('type') if type is None: raise common.BadData(message="missing type", at=dict(key=key)) type = self.process_value(type, self.get_property(None, 'type')) type = self.get_thing(type) # when type is changed, consider as all object is modified and don't compare with prev data. if prev_data and prev_data.get('type') != type.key: prev_data = None data = self.process_data(data, type, prev_data) for k in common.READ_ONLY_PROPERTIES: data.pop(k, None) prev_data and prev_data.pop(k, None) if data == prev_data: return None else: return data
def from_json(s): try: return simplejson.loads(s) except ValueError, e: raise common.BadData(message="Bad JSON: " + str(e))
def to_int(value, key): try: return int(value) except: raise common.BadData(message="Bad integer value for %s: %s" % (repr(key), repr(value)))
def assert_type_required(self): type_required = any(c.key not in common.COMMON_PROPERTIES for c in self.conditions if not isinstance(c, Query)) if type_required and self.get_type() is None: raise common.BadData(message="missing 'type' in query")
def validate_properties(self, data): rx = web.re_compile('^[a-z][a-z0-9_]*$') for key in data: if not rx.match(key): raise common.BadData(message="Bad Property: %s" % repr(key), at=dict(key=self.key))
raise common.TypeMismatch(expected_type, type_found, at=at, value=value) else: if type_found == '/type/string': value = common.Reference(value) type_found = common.find_type(value) if type_found == '/type/object': type_found = self.get_type(value) # type is not found only when the thing id not found. if type_found is None: raise common.NotFound(key=unicode(value), at=at) if expected_type != type_found: raise common.BadData(message='expected %s, found %s' % (property.expected_type.key, type_found), at=at, value=value) return value class WriteQueryProcessor: def __init__(self, store, author): self.store = store self.author = author def process(self, query): p = SaveProcessor(self.store, self.author) for q in serialize(query): q = common.parse_query(q) if not isinstance(q, dict) or q.get('key') is None: