commit
721beef8c8
6
backend/flask/src/.gitignore
vendored
Normal file
6
backend/flask/src/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
bin/
|
||||
lib/
|
||||
include/
|
||||
clipperz.egg-info/
|
||||
.Python
|
||||
app.db
|
@ -1,3 +1,4 @@
|
||||
"""Clipperz API handler."""
|
||||
import json
|
||||
import random
|
||||
import hashlib
|
||||
@ -12,27 +13,36 @@ from .exceptions import InvalidUsage
|
||||
from .models import User, Record, RecordVersion, OneTimePassword
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ==============================================================================
|
||||
# Helpers
|
||||
#==============================================================================
|
||||
# ==============================================================================
|
||||
def randomSeed():
|
||||
"""Generate a random seed."""
|
||||
return hex(random.getrandbits(32*8))[2:-1]
|
||||
|
||||
|
||||
def clipperzHash(aString):
|
||||
"""Calculate a clipperz hash.
|
||||
|
||||
sha256(sha256(aString))
|
||||
"""
|
||||
firstRound = hashlib.sha256()
|
||||
firstRound.update(aString)
|
||||
result = hashlib.sha256()
|
||||
result.update(firstRound.digest())
|
||||
|
||||
return result.hexdigest()
|
||||
#==============================================================================
|
||||
# ==============================================================================
|
||||
# Method handlers
|
||||
#==============================================================================
|
||||
# ==============================================================================
|
||||
|
||||
|
||||
class HandlerMixin:
|
||||
|
||||
"""Mixin for handling requests."""
|
||||
|
||||
def handle_request(self, request):
|
||||
"""Default method to handle a request."""
|
||||
parameters = json.loads(request.form['parameters'])
|
||||
app.logger.debug('raw parameters: %s', parameters)
|
||||
parameters = parameters['parameters']
|
||||
@ -50,7 +60,14 @@ class HandlerMixin:
|
||||
|
||||
|
||||
class registration(HandlerMixin):
|
||||
|
||||
"""Registration handler."""
|
||||
|
||||
def completeRegistration(self, parameters, request):
|
||||
"""Complete a registration.
|
||||
|
||||
Create a new user.
|
||||
"""
|
||||
credentials = parameters['credentials']
|
||||
data = parameters['user']
|
||||
user = User()
|
||||
@ -63,11 +80,21 @@ class registration(HandlerMixin):
|
||||
|
||||
|
||||
class handshake(HandlerMixin):
|
||||
|
||||
"""Handshake handler.
|
||||
|
||||
This handles the logon process.
|
||||
"""
|
||||
|
||||
srp_n = '115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3'
|
||||
srp_g = 2
|
||||
srp_n = long(srp_n, 16)
|
||||
|
||||
def connect(self, parameters, request):
|
||||
"""Process a connect request.
|
||||
|
||||
Attempt to log in by processing the parameters.
|
||||
"""
|
||||
result = {}
|
||||
session['C'] = parameters['parameters']['C']
|
||||
session['A'] = parameters['parameters']['A']
|
||||
@ -127,8 +154,12 @@ class handshake(HandlerMixin):
|
||||
return jsonify({'result': result})
|
||||
|
||||
def credentialCheck(self, parameters, request):
|
||||
"""Check credentials.
|
||||
|
||||
Handles the SRP process.
|
||||
"""
|
||||
country = 'US'
|
||||
# hard-coded for development
|
||||
# hard-coded for development/personal use.
|
||||
result = {
|
||||
'accountInfo': {
|
||||
'features': [
|
||||
@ -203,14 +234,15 @@ class handshake(HandlerMixin):
|
||||
return jsonify({'result': result})
|
||||
|
||||
def oneTimePassword(self, parameters, request):
|
||||
#"parameters": {
|
||||
#"message": "oneTimePassword",
|
||||
#"version": "0.2",
|
||||
#"parameters": {
|
||||
# "oneTimePasswordKey": "03bd882...396082c",
|
||||
# "oneTimePasswordKeyChecksum": "f73f629...041031d"
|
||||
#}
|
||||
#}
|
||||
"""Handle one time password logins."""
|
||||
# "parameters": {
|
||||
# "message": "oneTimePassword",
|
||||
# "version": "0.2",
|
||||
# "parameters": {
|
||||
# "oneTimePasswordKey": "03bd882...396082c",
|
||||
# "oneTimePasswordKeyChecksum": "f73f629...041031d"
|
||||
# }
|
||||
# }
|
||||
result = {}
|
||||
|
||||
try:
|
||||
@ -237,8 +269,12 @@ class handshake(HandlerMixin):
|
||||
|
||||
|
||||
class message(HandlerMixin):
|
||||
|
||||
"""Handle messages once logged in."""
|
||||
|
||||
@login_required
|
||||
def getUserDetails(self, parameters, request):
|
||||
"""Get a user's details."""
|
||||
app.logger.debug(parameters)
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
@ -252,7 +288,7 @@ class message(HandlerMixin):
|
||||
# Online results
|
||||
# {"result":
|
||||
# {
|
||||
# "header": "{\"records\":{\"index\":{\"383036...eeefbe48\":\"0\"},\"data\":\"zrhb3/791SDdb48v3vXfPzeDrv0Jhs4rAaOKHx+jDF6pwm/qi9DGSR0JwrprOgwv3bjYJgU2xHA8cuA0bPvABHSHK6fnGwvhSlyYjskY2Cy/WbRJhcA4kw+VUsOjZPRxtM8bSJnSxViAXsghTcya6+5M3MdMJHE=\"},\"directLogins\":{\"index\":{},\"data\":\"s7KYzHwKISmjYufv9h0mpTiM\"},\"preferences\":{\"data\":\"mf8fWjpOQjlV18ukEO9FN3LP\"},\"oneTimePasswords\":{\"data\":\"8tV1yRHv30lsl3FadG9YnTOo\"},\"version\":\"0.1\"}",
|
||||
# "header": "{\"records\":{\"index\":{\"383036...eeefbe48\":\"0\"},\"data\":\"zrhb3/791SDdb48v3vXfPzeDrv0Jhs4rAaOKHx+jDF6pwm/qi9DGSR0JwrprOgwv3bjYJgU2xHA8cuA0bPvABHSHK6fnGwvhSlyYjskY2Cy/WbRJhcA4kw+VUsOjZPRxtM8bSJnSxViAXsghTcya6+5M3MdMJHE=\"},\"directLogins\":{\"index\":{},\"data\":\"s7KYzHwKISmjYufv9h0mpTiM\"},\"preferences\":{\"data\":\"mf8fWjpOQjlV18ukEO9FN3LP\"},\"oneTimePasswords\":{\"data\":\"8tV1yRHv30lsl3FadG9YnTOo\"},\"version\":\"0.1\"}", # NOQA
|
||||
# "lock": "3D4B4501-D7A9-6E4F-A487-9428C0B6E79D",
|
||||
# "version": "0.4",
|
||||
# "recordsStats": {
|
||||
@ -266,8 +302,8 @@ class message(HandlerMixin):
|
||||
# }
|
||||
# }
|
||||
# Dev results
|
||||
#{"result":
|
||||
# {"header": "{\"records\":{\"index\":{\"843a95d8...5f734b\":\"1\"},\"data\":\"fKgc5Jt9JH/CibCIpcRmwyLuLIvufWchNJga7GoFcWT9K8LR+ai0BvzWBUxcPccivE9zPv2Swe5E8wPEIc+Lv0U73NobJEct7WqBcCdLxszBE1SokxPEZDUVdWVQtAiwgOS219inCFmI5CaB\"},\"directLogins\":{\"index\":{},\"data\":\"rnMQBB81ezh6JKNGXkDCyY+q\"},\"preferences\":{\"data\":\"9jzR9Goo5PGpXbAdmsXHuQGp\"},\"oneTimePasswords\":{\"data\":\"iXEUuQGskZhMyHEwU+3tRGQM\"},\"version\":\"0.1\"}",
|
||||
# {"result":
|
||||
# {"header": "{\"records\":{\"index\":{\"843a95d8...5f734b\":\"1\"},\"data\":\"fKgc5Jt9JH/CibCIpcRmwyLuLIvufWchNJga7GoFcWT9K8LR+ai0BvzWBUxcPccivE9zPv2Swe5E8wPEIc+Lv0U73NobJEct7WqBcCdLxszBE1SokxPEZDUVdWVQtAiwgOS219inCFmI5CaB\"},\"directLogins\":{\"index\":{},\"data\":\"rnMQBB81ezh6JKNGXkDCyY+q\"},\"preferences\":{\"data\":\"9jzR9Goo5PGpXbAdmsXHuQGp\"},\"oneTimePasswords\":{\"data\":\"iXEUuQGskZhMyHEwU+3tRGQM\"},\"version\":\"0.1\"}", # NOQA
|
||||
# "recordStats": {
|
||||
# "843a95d8...5f734b": {
|
||||
# "updateDate": "Sun, 12 Apr 2015 13:08:44 GMT"
|
||||
@ -295,6 +331,7 @@ class message(HandlerMixin):
|
||||
|
||||
@login_required
|
||||
def saveChanges(self, parameters, request):
|
||||
"""Save changes to a user's settings."""
|
||||
result = {}
|
||||
parameters = parameters['parameters']
|
||||
if ('user' not in parameters
|
||||
@ -340,7 +377,8 @@ class message(HandlerMixin):
|
||||
|
||||
@login_required
|
||||
def getRecordDetail(self, parameters, request):
|
||||
#{
|
||||
"""Get details about a record."""
|
||||
# {
|
||||
# "parameters": {
|
||||
# "srpSharedSecret": "bf79ad3cf0c1...63462a9fb560",
|
||||
# "message": "getRecordDetail",
|
||||
@ -348,7 +386,7 @@ class message(HandlerMixin):
|
||||
# "reference": "e3a5856...20e080fc97f13c14c"
|
||||
# }
|
||||
# }
|
||||
#}
|
||||
# }
|
||||
app.logger.debug(parameters)
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
@ -404,13 +442,14 @@ class message(HandlerMixin):
|
||||
|
||||
@login_required
|
||||
def getOneTimePasswordsDetails(self, parameters, request):
|
||||
#{
|
||||
"""Get details about a one time password."""
|
||||
# {
|
||||
# "parameters": {
|
||||
# "srpSharedSecret": "bf79ad3cf0c1...63462a9fb560",
|
||||
# "message": "getOneTimePasswordsDetails",
|
||||
# "parameters": {}
|
||||
# }
|
||||
#}
|
||||
# }
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
'Mal-formed message format.',
|
||||
@ -425,20 +464,24 @@ class message(HandlerMixin):
|
||||
|
||||
otps = OneTimePassword().query.filter_by(user=current_user).all()
|
||||
for otp in otps:
|
||||
#{"e8541...af0c6b951":{"status":"ACTIVE"}}
|
||||
# {"e8541...af0c6b951":{"status":"ACTIVE"}}
|
||||
result[otp.reference] = {'status': otp.status}
|
||||
|
||||
return jsonify({'result': result})
|
||||
|
||||
@login_required
|
||||
def getLoginHistory(self, parameters, request):
|
||||
#{
|
||||
"""Get login history.
|
||||
|
||||
Not currently fully implemented.
|
||||
"""
|
||||
# {
|
||||
# "parameters": {
|
||||
# "srpSharedSecret": "bf79ad3cf0c1...63462a9fb560",
|
||||
# "message": "getOneTimePasswordsDetails",
|
||||
# "parameters": {}
|
||||
# }
|
||||
#}
|
||||
# }
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
'Mal-formed message format.',
|
||||
@ -462,6 +505,7 @@ class message(HandlerMixin):
|
||||
|
||||
@login_required
|
||||
def addNewOneTimePassword(self, parameters, request):
|
||||
"""Add a new one time password."""
|
||||
# "parameters": {
|
||||
# "message": "addNewOneTimePassword",
|
||||
# "srpSharedSecret": "1e8e037a8...85680f931d45dfc20472cf9d1",
|
||||
@ -481,7 +525,7 @@ class message(HandlerMixin):
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#}
|
||||
# }
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
'Mal-formed message format.',
|
||||
@ -524,6 +568,7 @@ class message(HandlerMixin):
|
||||
return jsonify({'result': result})
|
||||
|
||||
def echo(self, parameters, request):
|
||||
"""Check the status of the session."""
|
||||
result = {}
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
@ -549,6 +594,7 @@ class message(HandlerMixin):
|
||||
|
||||
@login_required
|
||||
def deleteUser(self, parameters, request):
|
||||
"""Delete a user and all of its records."""
|
||||
result = {}
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
@ -573,7 +619,8 @@ class message(HandlerMixin):
|
||||
|
||||
@login_required
|
||||
def upgradeUserCredentials(self, parameters, request):
|
||||
#{"parameters":{"message":"upgradeUserCredentials","srpSharedSecret":"36...d6","parameters":{"credentials":{"C":"59d02038fdb47cee5b7837a697bc8ff41cc66d8844c8fce844cdf45b0b08b1e4","s":"fe40513b99fbaca9bfe51b8d6e9b3eb42b1e01ce8b0ae32461bec0294c1030ed","v":"300b92f4a3e34034d78cd5081f8db36dbf2a4c5f7a41db6954518815a3554278","version":"0.2"},"user":{"header":"{\"records\":{\"index\":{},\"data\":\"VIIDc5vFNoIflyXF8syb8fRS\"},\"directLogins\":{\"index\":{},\"data\":\"9elg3tu2UqsJ0zbUAdQkLE69\"},\"preferences\":{\"data\":\"Sbwar35Ynd/XobuAm4K66lqj\"},\"oneTimePasswords\":{\"data\":\"tAcTsWVTwALSfxXvCChHi4FD\"},\"version\":\"0.1\"}","statistics":"","version":"0.4","lock":null}}}}
|
||||
"""Upgrade a user's credentials to a new password."""
|
||||
# {"parameters":{"message":"upgradeUserCredentials","srpSharedSecret":"36...d6","parameters":{"credentials":{"C":"59d02038fdb47cee5b7837a697bc8ff41cc66d8844c8fce844cdf45b0b08b1e4","s":"fe40513b99fbaca9bfe51b8d6e9b3eb42b1e01ce8b0ae32461bec0294c1030ed","v":"300b92f4a3e34034d78cd5081f8db36dbf2a4c5f7a41db6954518815a3554278","version":"0.2"},"user":{"header":"{\"records\":{\"index\":{},\"data\":\"VIIDc5vFNoIflyXF8syb8fRS\"},\"directLogins\":{\"index\":{},\"data\":\"9elg3tu2UqsJ0zbUAdQkLE69\"},\"preferences\":{\"data\":\"Sbwar35Ynd/XobuAm4K66lqj\"},\"oneTimePasswords\":{\"data\":\"tAcTsWVTwALSfxXvCChHi4FD\"},\"version\":\"0.1\"}","statistics":"","version":"0.4","lock":null}}}} # NOQA
|
||||
result = {}
|
||||
if 'srpSharedSecret' not in parameters:
|
||||
raise InvalidUsage(
|
||||
@ -614,7 +661,11 @@ class message(HandlerMixin):
|
||||
|
||||
|
||||
class logout(HandlerMixin):
|
||||
|
||||
"""Logout handler."""
|
||||
|
||||
def handle_request(self, request):
|
||||
"""Handle a logout request."""
|
||||
result = {}
|
||||
logout_user()
|
||||
session.clear()
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Clipperz models."""
|
||||
import datetime
|
||||
|
||||
from flask.ext.login import UserMixin
|
||||
@ -6,15 +7,18 @@ from clipperz import app, db
|
||||
|
||||
|
||||
class User(db.Model, UserMixin):
|
||||
|
||||
"""Clipperz User model."""
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(), unique=True, index=True)
|
||||
username = db.Column(db.String(255), unique=True, index=True)
|
||||
srp_s = db.Column(db.String(128))
|
||||
srp_v = db.Column(db.String(128))
|
||||
header = db.Column(db.Text())
|
||||
statistics = db.Column(db.Text())
|
||||
auth_version = db.Column(db.String())
|
||||
version = db.Column(db.String())
|
||||
lock = db.Column(db.String())
|
||||
auth_version = db.Column(db.String(255))
|
||||
version = db.Column(db.String(255))
|
||||
lock = db.Column(db.String(255))
|
||||
records = db.relationship(
|
||||
'Record',
|
||||
backref='user',
|
||||
@ -29,12 +33,14 @@ class User(db.Model, UserMixin):
|
||||
update_date = db.Column(db.DateTime(), nullable=True)
|
||||
|
||||
def updateCredentials(self, credentials):
|
||||
"""Update user credentials."""
|
||||
self.username = credentials['C']
|
||||
self.srp_s = credentials['s']
|
||||
self.srp_v = credentials['v']
|
||||
self.auth_version = credentials['version']
|
||||
|
||||
def update(self, data):
|
||||
"""Update user object."""
|
||||
self.header = data['header']
|
||||
self.statistics = data['statistics']
|
||||
self.version = data['version']
|
||||
@ -44,24 +50,33 @@ class User(db.Model, UserMixin):
|
||||
self.offline_saved = False
|
||||
|
||||
def __repr__(self):
|
||||
"""User representation."""
|
||||
return '<User %r>' % (self.username)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class RecordVersion(db.Model):
|
||||
|
||||
"""
|
||||
Model a RecordVersion.
|
||||
|
||||
RecordVersion store attributes associated with a specific version of a
|
||||
record.
|
||||
"""
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
reference = db.Column(db.String(), unique=True, index=True)
|
||||
reference = db.Column(db.String(255), unique=True, index=True)
|
||||
header = db.Column(db.Text())
|
||||
data = db.Column(db.Text())
|
||||
api_version = db.Column(db.String())
|
||||
api_version = db.Column(db.String(255))
|
||||
version = db.Column(db.Integer())
|
||||
previous_version_key = db.Column(db.String())
|
||||
previous_version_key = db.Column(db.String(255))
|
||||
previous_version_id = db.Column(db.Integer(),
|
||||
db.ForeignKey('record_version.id'))
|
||||
creation_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
update_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
access_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
creation_date = db.Column(db.DateTime())
|
||||
update_date = db.Column(db.DateTime())
|
||||
access_date = db.Column(db.DateTime())
|
||||
|
||||
record_id = db.Column(db.Integer(),
|
||||
db.ForeignKey('record.id'),
|
||||
@ -72,7 +87,12 @@ class RecordVersion(db.Model):
|
||||
order_by=id,
|
||||
cascade='all,delete'))
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize a record version."""
|
||||
self.creation_date = datetime.datetime.utcnow()
|
||||
|
||||
def update(self, someData):
|
||||
"""Update a record version."""
|
||||
app.logger.debug(someData)
|
||||
recordVersionData = someData['currentRecordVersion']
|
||||
self.reference = recordVersionData['reference']
|
||||
@ -83,26 +103,37 @@ class RecordVersion(db.Model):
|
||||
self.update_date = datetime.datetime.utcnow()
|
||||
|
||||
self.record.update(someData['record'], self)
|
||||
#------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class Record(db.Model):
|
||||
|
||||
"""Model a record.
|
||||
|
||||
A Record has multiple record versions.
|
||||
"""
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_id = db.Column(db.ForeignKey('user.id'))
|
||||
reference = db.Column(db.String(), unique=True, index=True)
|
||||
reference = db.Column(db.String(255), unique=True, index=True)
|
||||
data = db.Column(db.Text())
|
||||
api_version = db.Column(db.String())
|
||||
api_version = db.Column(db.String(255))
|
||||
version = db.Column(db.Integer(), default=0)
|
||||
creation_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
update_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
access_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
creation_date = db.Column(db.DateTime())
|
||||
update_date = db.Column(db.DateTime())
|
||||
access_date = db.Column(db.DateTime())
|
||||
|
||||
current_record_version = db.relationship(
|
||||
'RecordVersion',
|
||||
uselist=False,
|
||||
cascade='save-update, merge, delete, delete-orphan')
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize a record."""
|
||||
self.creation_date = datetime.datetime.utcnow()
|
||||
|
||||
def update(self, data, record_version):
|
||||
"""Update a record."""
|
||||
self.reference = data['reference']
|
||||
self.data = data['data']
|
||||
self.api_version = data['version']
|
||||
@ -113,23 +144,34 @@ class Record(db.Model):
|
||||
else:
|
||||
self.version = 1
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class OneTimePassword(db.Model):
|
||||
|
||||
"""Model a OneTimePassword.
|
||||
|
||||
OneTimePasswords are used to log in to clipperz only once.
|
||||
"""
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
user_id = db.Column(db.ForeignKey('user.id'))
|
||||
status = db.Column(db.String())
|
||||
reference = db.Column(db.String(), unique=True)
|
||||
key_value = db.Column(db.String())
|
||||
key_checksum = db.Column(db.String())
|
||||
status = db.Column(db.String(255))
|
||||
reference = db.Column(db.String(255), unique=True)
|
||||
key_value = db.Column(db.String(255))
|
||||
key_checksum = db.Column(db.String(255))
|
||||
data = db.Column(db.Text())
|
||||
version = db.Column(db.String())
|
||||
creation_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
version = db.Column(db.String(255))
|
||||
creation_date = db.Column(db.DateTime())
|
||||
request_date = db.Column(db.DateTime())
|
||||
usage_date = db.Column(db.DateTime())
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize a OneTimePassword."""
|
||||
self.creation_date = datetime.datetime.utcnow()
|
||||
|
||||
def update(self, someParameters, aStatus):
|
||||
"""Update a one time password."""
|
||||
self.reference = someParameters['reference']
|
||||
self.key_value = someParameters['key']
|
||||
self.key_checksum = someParameters['keyChecksum']
|
||||
@ -138,14 +180,22 @@ class OneTimePassword(db.Model):
|
||||
self.status = aStatus
|
||||
|
||||
def reset(self, aStatus):
|
||||
"""Reset a one time password."""
|
||||
self.data = ""
|
||||
self.status = aStatus
|
||||
return self
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class Session(db.Model):
|
||||
|
||||
"""Model a session."""
|
||||
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
sessionId = db.Column(db.String())
|
||||
access_date = db.Column(db.DateTime(), default=datetime.datetime.utcnow)
|
||||
sessionId = db.Column(db.String(255))
|
||||
access_date = db.Column(db.DateTime())
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize a session."""
|
||||
self.access_date = datetime.datetime.utcnow()
|
||||
|
@ -1,23 +1,30 @@
|
||||
from flask import session, request, g, jsonify
|
||||
"""Clipperz views."""
|
||||
from flask import session, request, g
|
||||
from clipperz import app, db, lm
|
||||
from .models import User
|
||||
from .api import *
|
||||
from .api import * # NOQA
|
||||
from .exceptions import InvalidUsage
|
||||
from flask.ext.login import login_required
|
||||
|
||||
|
||||
@lm.user_loader
|
||||
def load_user(id):
|
||||
"""Load a user.
|
||||
|
||||
Converts a user id in to a User object.
|
||||
"""
|
||||
return User.query.get(int(id))
|
||||
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
"""Store the current user."""
|
||||
g.user = current_user
|
||||
|
||||
|
||||
@app.teardown_appcontext
|
||||
def shutdown_session(exception=None):
|
||||
"""Remove the session from the database."""
|
||||
db.session.remove()
|
||||
|
||||
|
||||
@ -26,6 +33,7 @@ def shutdown_session(exception=None):
|
||||
@app.route('/delta/dump/<string:frontend_version>')
|
||||
@login_required
|
||||
def dump(frontend_version):
|
||||
"""Return JSON for a user's data."""
|
||||
user = User().query.filter_by(username=session['C']).one()
|
||||
|
||||
if (user != g.user):
|
||||
@ -104,21 +112,25 @@ def dump(frontend_version):
|
||||
|
||||
@app.route('/beta/<path:path>')
|
||||
def beta(path):
|
||||
"""Fallback for serving beta version."""
|
||||
return send_from_directory('beta', path)
|
||||
|
||||
|
||||
@app.route('/gamma/<path:path>')
|
||||
def gamma(path):
|
||||
"""Fallback for serving gamma version."""
|
||||
return send_from_directory('gamma', path)
|
||||
|
||||
|
||||
@app.route('/delta/<path:path>')
|
||||
def delta(path):
|
||||
"""Fallback for serving delta version."""
|
||||
return send_from_directory('delta', path)
|
||||
|
||||
|
||||
@app.route('/pm', methods=['GET', 'OPTIONS', 'POST'])
|
||||
def pm():
|
||||
"""Main request handler."""
|
||||
method = request.form['method']
|
||||
if method not in globals():
|
||||
raise InvalidUsage('This method is not yet implemented',
|
||||
|
@ -2,7 +2,7 @@
|
||||
from migrate.versioning import api
|
||||
from config import SQLALCHEMY_DATABASE_URI
|
||||
from config import SQLALCHEMY_MIGRATE_REPO
|
||||
from app import db
|
||||
from clipperz import db
|
||||
import os.path
|
||||
db.create_all()
|
||||
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
import imp
|
||||
from migrate.versioning import api
|
||||
from app import db
|
||||
from clipperz import db
|
||||
from config import SQLALCHEMY_DATABASE_URI
|
||||
from config import SQLALCHEMY_MIGRATE_REPO
|
||||
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
|
||||
|
97
backend/flask/src/db_repository/versions/001_migration.py
Normal file
97
backend/flask/src/db_repository/versions/001_migration.py
Normal file
@ -0,0 +1,97 @@
|
||||
from sqlalchemy import *
|
||||
from migrate import *
|
||||
|
||||
|
||||
from migrate.changeset import schema
|
||||
pre_meta = MetaData()
|
||||
post_meta = MetaData()
|
||||
one_time_password = Table('one_time_password', post_meta,
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('user_id', Integer),
|
||||
Column('status', String),
|
||||
Column('reference', String),
|
||||
Column('key_value', String),
|
||||
Column('key_checksum', String),
|
||||
Column('data', Text),
|
||||
Column('version', String),
|
||||
Column('creation_date', DateTime),
|
||||
Column('request_date', DateTime),
|
||||
Column('usage_date', DateTime),
|
||||
)
|
||||
|
||||
record = Table('record', post_meta,
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('user_id', Integer),
|
||||
Column('reference', String),
|
||||
Column('data', Text),
|
||||
Column('api_version', String),
|
||||
Column('version', Integer, default=ColumnDefault(0)),
|
||||
Column('creation_date', DateTime),
|
||||
Column('update_date', DateTime),
|
||||
Column('access_date', DateTime),
|
||||
)
|
||||
|
||||
record_version = Table('record_version', post_meta,
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('reference', String),
|
||||
Column('header', Text),
|
||||
Column('data', Text),
|
||||
Column('api_version', String),
|
||||
Column('version', Integer),
|
||||
Column('previous_version_key', String),
|
||||
Column('previous_version_id', Integer),
|
||||
Column('creation_date', DateTime),
|
||||
Column('update_date', DateTime),
|
||||
Column('access_date', DateTime),
|
||||
Column('record_id', Integer, nullable=False),
|
||||
)
|
||||
|
||||
session = Table('session', post_meta,
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('sessionId', String),
|
||||
Column('access_date', DateTime),
|
||||
)
|
||||
|
||||
sessions = Table('sessions', post_meta,
|
||||
Column('key', String(length=250), primary_key=True, nullable=False),
|
||||
Column('value', LargeBinary, nullable=False),
|
||||
)
|
||||
|
||||
user = Table('user', post_meta,
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('username', String),
|
||||
Column('srp_s', String(length=128)),
|
||||
Column('srp_v', String(length=128)),
|
||||
Column('header', Text),
|
||||
Column('statistics', Text),
|
||||
Column('auth_version', String),
|
||||
Column('version', String),
|
||||
Column('lock', String),
|
||||
Column('offline_saved', Boolean, default=ColumnDefault(False)),
|
||||
Column('update_date', DateTime),
|
||||
)
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
# Upgrade operations go here. Don't create your own engine; bind
|
||||
# migrate_engine to your metadata
|
||||
pre_meta.bind = migrate_engine
|
||||
post_meta.bind = migrate_engine
|
||||
post_meta.tables['one_time_password'].create()
|
||||
post_meta.tables['record'].create()
|
||||
post_meta.tables['record_version'].create()
|
||||
post_meta.tables['session'].create()
|
||||
post_meta.tables['sessions'].create()
|
||||
post_meta.tables['user'].create()
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
# Operations to reverse the above upgrade go here.
|
||||
pre_meta.bind = migrate_engine
|
||||
post_meta.bind = migrate_engine
|
||||
post_meta.tables['one_time_password'].drop()
|
||||
post_meta.tables['record'].drop()
|
||||
post_meta.tables['record_version'].drop()
|
||||
post_meta.tables['session'].drop()
|
||||
post_meta.tables['sessions'].drop()
|
||||
post_meta.tables['user'].drop()
|
@ -45,6 +45,7 @@ setup(
|
||||
install_requires=['Flask>=0.10.1',
|
||||
'Flask-SQLAlchemy>=1.0',
|
||||
'SQLAlchemy>=0.8.2',
|
||||
'SQLAlchemy-migrate',
|
||||
'Flask-Login',
|
||||
'Flask-KVSession',
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user