user.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import base64
  2. import hashlib
  3. import random
  4. import re
  5. import string
  6. import dokk.sparql as sparql
  7. from bottle import request, response
  8. from datetime import datetime, timezone
  9. from dokk import random, settings
  10. from string import Template
  11. def exists(username):
  12. """
  13. Check if a User already exists.
  14. :param username: Username of the user.
  15. """
  16. query = Template("""
  17. PREFIX : <dokk:/>
  18. PREFIX dokk: <https://ontology.dokk.org/>
  19. ASK {
  20. [] a dokk:User ;
  21. dokk:username "$username" .
  22. }
  23. """).substitute(username = sparql.escape_literal(username))
  24. response = sparql.query_instance(query)
  25. return response['boolean']
  26. def create(username, password):
  27. """
  28. Add a new User.
  29. :param username: Username of the new user.
  30. :param password: Password for the new user.
  31. """
  32. salt = random.ascii_string(64)
  33. query = Template("""
  34. PREFIX : <dokk:/>
  35. PREFIX dokk: <https://ontology.dokk.org/>
  36. PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
  37. INSERT {
  38. <dokk:/$uri> a dokk:User ;
  39. dokk:username "$username" ;
  40. dokk:password ?password ;
  41. dokk:salt "$salt" ;
  42. dokk:registration_datetime "$registered"^^xsd:dateTime ;
  43. dokk:banned false .
  44. }
  45. WHERE {
  46. BIND(SHA512(CONCAT("$salt", ":", "$password")) AS ?password)
  47. };
  48. """).substitute(
  49. uri = sparql.escape_term(username),
  50. username = sparql.escape_literal(username),
  51. password = sparql.escape_literal(password),
  52. salt = sparql.escape_literal(salt),
  53. registered = sparql.escape_literal(datetime.now(timezone.utc).isoformat()))
  54. sparql.update_instance(query)
  55. def get(username):
  56. """
  57. Retrieve a single user.
  58. :param username: Username of the user to be retrieved.
  59. """
  60. query = Template("""
  61. PREFIX : <dokk:/>
  62. PREFIX dokk: <https://ontology.dokk.org/>
  63. DESCRIBE *
  64. WHERE {
  65. ?s a dokk:User ;
  66. dokk:username "$username" .
  67. }
  68. """).substitute(username = sparql.escape_literal(username))
  69. response = sparql.query_instance(query)
  70. return response
  71. def get_from_password(username, password):
  72. """
  73. Retrieve a single user with password validation.
  74. :param username: Username of the user to be retrieved.
  75. :param password: User password.
  76. """
  77. query = Template("""
  78. PREFIX : <dokk:/>
  79. PREFIX dokk: <https://ontology.dokk.org/>
  80. DESCRIBE *
  81. WHERE {
  82. ?s a dokk:User ;
  83. dokk:username "$username" ;
  84. dokk:salt ?salt ;
  85. dokk:password ?password .
  86. FILTER (?password = SHA512(CONCAT(?salt, ":", "$password")))
  87. }
  88. """).substitute(
  89. username = sparql.escape_literal(username),
  90. password = sparql.escape_literal(password))
  91. response = sparql.query_instance(query)
  92. return response
  93. def get_from_session():
  94. """
  95. Restore a user by reading its session token in the cookie.
  96. """
  97. session_token = request.get_cookie(
  98. key = settings['session.name'],
  99. secret = settings['cookies.secret'])
  100. if not session_token:
  101. return None
  102. # Retrieve from database
  103. query = Template("""
  104. PREFIX : <dokk:/>
  105. PREFIX dokk: <https://ontology.dokk.org/>
  106. DESCRIBE *
  107. WHERE {
  108. ?s a dokk:User ;
  109. dokk:session_token "$token" .
  110. }
  111. """).substitute(token = sparql.escape_literal(session_token))
  112. user = sparql.query_instance(query)
  113. if 'username' not in user:
  114. return None
  115. return user
  116. def is_banned(username):
  117. """
  118. Check if a user is banned or not.
  119. :param username: Username of the user.
  120. """
  121. query = Template("""
  122. PREFIX : <dokk:/>
  123. PREFIX dokk: <https://ontology.dokk.org/>
  124. ASK {
  125. [] a dokk:User ;
  126. dokk:username "$username" ;
  127. dokk:banned true .
  128. }
  129. """).substitute(username = sparql.escape_literal(username))
  130. response = sparql.query_instance(query)
  131. return response['boolean']
  132. def is_signedin():
  133. """
  134. Check if a user is signed in or not.
  135. """
  136. return get_from_session() is not None
  137. def start_session(username, remember=False):
  138. """
  139. Start a new browser session.
  140. :param username: Username of the user.
  141. :param remember: "Remember me" or expire with browser.
  142. """
  143. session_token = random.ascii_string(64)
  144. # Create session cookie
  145. response.set_cookie(
  146. name = settings['session.name'],
  147. value = session_token,
  148. secret = settings['cookies.secret'],
  149. path = '/',
  150. # When to end the session
  151. max_age = settings['session.remember_me'] if remember else None,
  152. # HTTPS only
  153. secure = False,
  154. # Do not allow JavaScript to read this cookie
  155. httponly = True)
  156. # Store session token in the database, so that we can identify the signed in
  157. # user from the session token stored in the cookie
  158. query = Template("""
  159. PREFIX : <dokk:/>
  160. PREFIX dokk: <https://ontology.dokk.org/>
  161. PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
  162. DELETE { ?s dokk:session_token ?o }
  163. WHERE {
  164. ?s a dokk:User ;
  165. dokk:username "$username" ;
  166. ?p ?o .
  167. };
  168. INSERT { ?s dokk:session_token "$token" }
  169. WHERE {
  170. ?s a dokk:User ;
  171. dokk:username "$username" .
  172. };
  173. """).substitute(
  174. username = sparql.escape_literal(username),
  175. token = sparql.escape_literal(session_token))
  176. sparql.update_instance(query)
  177. # End the current open session
  178. def end_session():
  179. # Read user
  180. user = get_from_session()
  181. if not user:
  182. return
  183. # Delete session token from the database
  184. query = Template("""
  185. PREFIX : <dokk:/>
  186. PREFIX dokk: <https://ontology.dokk.org/>
  187. PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
  188. DELETE { ?s dokk:session_token ?o }
  189. WHERE {
  190. ?s a dokk:User ;
  191. dokk:username "$username" ;
  192. ?p ?o .
  193. }
  194. """).substitute(username = sparql.escape_literal(user['username']))
  195. sparql.update_instance(query)
  196. # Delete user cookie containing session token
  197. response.delete_cookie(settings['session.name'])