-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmodel.py
More file actions
154 lines (122 loc) · 4.55 KB
/
model.py
File metadata and controls
154 lines (122 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from peewee import *
from uuid import uuid4
from datetime import datetime
import yaml
import os
import hashlib
import secrets
dir_path = os.path.dirname(os.path.realpath(__file__))
db_yml = os.path.join(dir_path, "db.yml")
db_config = yaml.load(open(db_yml))
db = PostgresqlDatabase(db_config["database"],
user=db_config["user"],
password=db_config["password"],
host=db_config["host"])
# Development db.
#db = SqliteDatabase('crowd_captcha.db')
class DatabaseModel(Model):
class Meta:
database = db
class Application(DatabaseModel):
""" This represents the applications that use the system.
An application can't make requests to the app unless it's
registered.
uuid: the id of the application.
name: the common, human readable name of the application.
secret: the password that the application will use to validate the
requests.
"""
uuid = UUIDField(default=uuid4, primary_key=True)
name = CharField()
secret_hash = CharField()
salt = CharField()
@classmethod
def make_hash(Application, secret, salt):
sha256 = hashlib.sha256()
sha256.update(secret.encode())
sha256.update(salt.encode())
return sha256.hexdigest()
@classmethod
def create(Application, uuid, name, secret):
# "A good rule is of thumb is to use a salt that is the same size as
# the output of the hash function." (crackstation.net)
salt = secrets.token_hex(32)
secret_hash = Application.make_hash(secret, salt)
return super().create(uuid=uuid, name=name, secret_hash=secret_hash, salt=salt)
@classmethod
def auth(Application, uuid, secret):
app = Application.get_or_none(uuid)
if app is None:
return False
return app.secret_hash == Application.make_hash(secret, app.salt)
@classmethod
def is_valid(Application, uuid):
return (Application
.select()
.where(Application.uuid == uuid)
.count() == 1)
class Text(DatabaseModel):
""" This entity stores the texts to be served to the users.
uuid: the id of the text.
text: the text.
source: the source from where the text was retrieved (for instance,
the twitter url.
created: the date when it was created.
completed: whether the text has sufficient ratings or needs to be served
"""
uuid = UUIDField(default=uuid4, primary_key=True)
text = TextField()
source = CharField()
created = DateTimeField(default=datetime.now)
completed = BooleanField(default=False)
class Tag(DatabaseModel):
""" These are the instances of the user submitted tags.
uuid: the id of the tag.
application_uuid: the uuid of the application that showed the user
a given text.
text_uuid: the uuid of the text.
user_id: an identifier to map whose submittion it was.
score: a polarity score
timestamp: the date this was submitted.
validated: holds whether the form was submitted after the tag was
recorded.
"""
uuid = UUIDField(default=uuid4, primary_key=True)
application_uuid = ForeignKeyField(Application)
text_uuid = ForeignKeyField(Text)
user_id = CharField()
score = DoubleField()
created = DateTimeField(default=datetime.now)
validated = BooleanField(default=False)
# TODO: add foreign keys for secret_uuid (issue #12).
class Secret(DatabaseModel):
""" This stores the secrets given to users to pass the captcha.
uuid: the uuid of the secret.
application_uuid: the uuid of the application.
expiration: the expiration date of the secret.
validated: holds whether the form was submitted after the tag was
recorded.
"""
uuid = UUIDField(default=uuid4, primary_key=True)
application_uuid = UUIDField()
expiration = DateTimeField()
validated = BooleanField(default=False)
@classmethod
def is_valid(Secret, secret, app_uuid):
return (Secret
.select()
.where(Secret.uuid == secret &
Secret.application_uuid == app_uuid &
Secret.expiration <= datetime.now() &
Secret.validated == False)
.count() > 0)
@classmethod
def validate(Secret, secret):
(Secret
.update({ Secret.validated: True })
.where(Secret.uuid == secret)
.execute())
# TODO: add foreign keys for application_uuid and text_uuid (issue #12).
def create_tables():
with db:
db.create_tables([Application, Text, Tag, Secret])