jaaql-middleware-python 4.21.23__tar.gz → 4.21.25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. {jaaql-middleware-python-4.21.23/jaaql_middleware_python.egg-info → jaaql-middleware-python-4.21.25}/PKG-INFO +1 -1
  2. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/constants.py +2 -2
  3. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/documentation/documentation_public.py +25 -9
  4. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/email/email_manager_service.py +1 -1
  5. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/controller.py +8 -4
  6. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/exception_queries.py +9 -6
  7. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/generated_queries.py +13 -9
  8. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/model.py +56 -33
  9. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/openapi/swagger_documentation.py +1 -1
  10. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/scripts/01.install_domains.generated.sql +5 -5
  11. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/scripts/02.install_super_user.exceptions.sql +9 -2
  12. jaaql-middleware-python-4.21.25/jaaql/scripts/04.install_jaaql_data_structures.generated.sql +4083 -0
  13. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25/jaaql_middleware_python.egg-info}/PKG-INFO +1 -1
  14. jaaql-middleware-python-4.21.23/jaaql/scripts/04.install_jaaql_data_structures.generated.sql +0 -193
  15. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/LICENSE.txt +0 -0
  16. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/README.md +0 -0
  17. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/__init__.py +0 -0
  18. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/config/__init__.py +0 -0
  19. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/config/config-docker.ini +0 -0
  20. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/config/config-test.ini +0 -0
  21. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/config/config.ini +0 -0
  22. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/config_constants.py +0 -0
  23. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/db/__init__.py +0 -0
  24. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/db/db_interface.py +0 -0
  25. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/db/db_pg_interface.py +0 -0
  26. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/db/db_utils.py +0 -0
  27. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/db/db_utils_no_circ.py +0 -0
  28. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/documentation/__init__.py +0 -0
  29. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/documentation/documentation_internal.py +0 -0
  30. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/documentation/documentation_shared.py +0 -0
  31. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/email/__init__.py +0 -0
  32. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/email/email_manager.py +0 -0
  33. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/email/patch_ems.py +0 -0
  34. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/exceptions/__init__.py +0 -0
  35. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/exceptions/custom_http_status.py +0 -0
  36. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/exceptions/http_status_exception.py +0 -0
  37. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/exceptions/not_yet_implement_exception.py +0 -0
  38. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/interpreter/__init__.py +0 -0
  39. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/interpreter/interpret_jaaql.py +0 -0
  40. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/jaaql.py +0 -0
  41. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/migrations/__init__.py +0 -0
  42. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/migrations/migration_history.sql +0 -0
  43. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/migrations/migrations.py +0 -0
  44. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/__init__.py +0 -0
  45. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/base_controller.py +0 -0
  46. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/base_model.py +0 -0
  47. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/controller_interface.py +0 -0
  48. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/handmade_queries.py +0 -0
  49. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/model_interface.py +0 -0
  50. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/mvc/response.py +0 -0
  51. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/openapi/__init__.py +0 -0
  52. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/patch.py +0 -0
  53. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/scripts/03.install_super_user.handwritten.sql +0 -0
  54. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/scripts/05.install_jaaql.exceptions.sql +0 -0
  55. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/scripts/06.install_jaaql.handwritten.sql +0 -0
  56. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/scripts/swagger_template.html +0 -0
  57. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/services/__init__.py +0 -0
  58. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/services/cached_canned_query_service.py +0 -0
  59. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/services/migrations_manager_service.py +0 -0
  60. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/services/patch_mms.py +0 -0
  61. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/services/patch_shared_var_service.py +0 -0
  62. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/services/shared_var_service.py +0 -0
  63. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/utilities/__init__.py +0 -0
  64. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/utilities/crypt_utils.py +0 -0
  65. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/utilities/options.py +0 -0
  66. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/utilities/utils.py +0 -0
  67. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/utilities/utils_no_project_imports.py +0 -0
  68. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql/utilities/vault.py +0 -0
  69. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql_middleware_python.egg-info/SOURCES.txt +0 -0
  70. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql_middleware_python.egg-info/dependency_links.txt +0 -0
  71. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql_middleware_python.egg-info/requires.txt +0 -0
  72. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/jaaql_middleware_python.egg-info/top_level.txt +0 -0
  73. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/setup.cfg +0 -0
  74. {jaaql-middleware-python-4.21.23 → jaaql-middleware-python-4.21.25}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaaql-middleware-python
3
- Version: 4.21.23
3
+ Version: 4.21.25
4
4
  Summary: The jaaql package, allowing for rapid development and deployment of RESTful HTTP applications
5
5
  Home-page: https://github.com/JAAQL/JAAQL-middleware-python
6
6
  Author: Software Quality Measurement and Improvement bv
@@ -3,7 +3,6 @@ import socket
3
3
 
4
4
  KEY__username = "username"
5
5
  KEY__password = "password"
6
- KEY__dbms_user = "dbms_user"
7
6
  KEY__remember_me = "remember_me"
8
7
  KEY__attach_as = "attach_as"
9
8
  KEY__ip_address = "ip_address"
@@ -38,6 +37,7 @@ KEY__query = "query"
38
37
  KEY__security_key = "security_key"
39
38
  KEY__id = "id"
40
39
  KEY__oauth_token = "oauth_token"
40
+ KEY__accounts = "accounts"
41
41
 
42
42
  REGEX__dmbs_object_name = r'^[0-9a-zA-Z_]{1,32}$'
43
43
 
@@ -164,5 +164,5 @@ ROLE__postgres = "postgres"
164
164
 
165
165
  PROTOCOL__postgres = "postgresql://"
166
166
 
167
- VERSION = "4.21.23"
167
+ VERSION = "4.21.25"
168
168
 
@@ -33,6 +33,31 @@ DOCUMENTATION__create_account = SwaggerDocumentation(
33
33
  )
34
34
  )
35
35
 
36
+ DOCUMENTATION__create_account_batch = SwaggerDocumentation(
37
+ tags="Admin",
38
+ methods=SwaggerMethod(
39
+ method=REST__POST,
40
+ name="Create account batch",
41
+ description="Will create a batch of accounts, if you have privileges to do so",
42
+ body=SwaggerArgumentResponse(
43
+ name=KEY__accounts,
44
+ description="A list of the accounts",
45
+ arg_type=SwaggerList(
46
+ ARG_RES__username,
47
+ set_nullable(ARG_RES__password, "Whether the user is given a password"),
48
+ SwaggerArgumentResponse(
49
+ name=KEY__attach_as,
50
+ description="Whether the user will attach as a role",
51
+ arg_type=str,
52
+ required=False,
53
+ condition="Defaults to false",
54
+ example="my-role"
55
+ )
56
+ )
57
+ )
58
+ )
59
+ )
60
+
36
61
  DOCUMENTATION__password = SwaggerDocumentation(
37
62
  tags="Account",
38
63
  methods=SwaggerMethod(
@@ -166,15 +191,6 @@ DOCUMENTATION__emails = SwaggerDocumentation(
166
191
  )
167
192
  )
168
193
 
169
- ARG_RES__dbms_user = SwaggerArgumentResponse(
170
- name=KEY__dbms_user,
171
- description="The id of the dmbs user",
172
- arg_type=str,
173
- lower=True,
174
- strip=True,
175
- example=[str(uuid.uuid4()), str(uuid.uuid4())]
176
- )
177
-
178
194
  DOCUMENTATION__sign_up = SwaggerDocumentation(
179
195
  tags="Signup",
180
196
  # Explicitly set sign up to true to enforce design decision. We use the attempted insert of the current user (which can be the public user) as security
@@ -388,7 +388,7 @@ class EmailManagerService:
388
388
  if conn is None:
389
389
  raise Exception("Could not connect to email dispatcher '%s' with address '%s:%d'" % dispatcher_key, host, port)
390
390
 
391
- context = ssl.SSLContext(ssl.PROTOCOL_TLS)
391
+ context = ssl.create_default_context()
392
392
 
393
393
  conn.starttls(context=context)
394
394
  conn.login(username, password)
@@ -67,6 +67,10 @@ class JAAQLController(BaseJAAQLController):
67
67
  def accounts(connection: DBInterface, http_inputs: dict):
68
68
  self.model.create_account_with_potential_password(connection, **http_inputs)
69
69
 
70
+ @self.publish_route('/accounts/batch', DOCUMENTATION__create_account_batch)
71
+ def accounts(connection: DBInterface, http_inputs: dict):
72
+ self.model.create_account_batch_with_potential_password(connection, **http_inputs)
73
+
70
74
  @self.publish_route('/prepare', DOCUMENTATION__prepare)
71
75
  def prepare(http_inputs: dict, account_id: str):
72
76
  return self.model.prepare_queries(http_inputs, account_id)
@@ -88,16 +92,16 @@ class JAAQLController(BaseJAAQLController):
88
92
  self.model.attach_dispatcher_credentials(connection, http_inputs)
89
93
 
90
94
  @self.publish_route('/sign-up', DOCUMENTATION__sign_up)
91
- def sign_up(http_inputs: dict, account_id: str):
92
- return self.model.sign_up(http_inputs, account_id)
95
+ def sign_up(http_inputs: dict, account_id: str, is_the_anonymous_user: bool):
96
+ return self.model.sign_up(http_inputs, account_id, is_the_anonymous_user)
93
97
 
94
98
  @self.publish_route('/email', DOCUMENTATION__emails)
95
99
  def send_email(is_the_anonymous_user: bool, account_id: str, http_inputs: dict, username: str, auth_token: str):
96
100
  return self.model.send_email(is_the_anonymous_user, account_id, http_inputs, username, auth_token)
97
101
 
98
102
  @self.publish_route('/account/reset-password', DOCUMENTATION__reset_password)
99
- def reset_password(http_inputs: dict):
100
- return self.model.reset_password(http_inputs)
103
+ def reset_password(http_inputs: dict, is_the_anonymous_user: bool):
104
+ return self.model.reset_password(http_inputs, is_the_anonymous_user)
101
105
 
102
106
  @self.publish_route('/security-event', DOCUMENTATION__security_event)
103
107
  def security_event(http_inputs: dict):
@@ -1,5 +1,5 @@
1
1
  """
2
- This script was generated from jaaql.exceptions.fxls at 2023-11-02, 21:56:22
2
+ This script was generated from jaaql.exceptions.fxls at 2024-02-11, 00:36:29
3
3
  """
4
4
 
5
5
  from jaaql.utilities.crypt_utils import get_repeatable_salt
@@ -11,8 +11,8 @@ def add_account_password(
11
11
  account__id, account_password__hash
12
12
  ):
13
13
  account_password__uuid = account_password__insert(
14
- connection, encryption_key, account__id,
15
- account_password__hash,
14
+ connection, encryption_key, account__id,
15
+ account_password__hash,
16
16
  encryption_salts={KG__account_password__hash: get_repeatable_salt(vault_repeatable_salt, account__id)}
17
17
  )[KG__account_password__uuid]
18
18
 
@@ -83,9 +83,10 @@ def fetch_account_from_username(
83
83
  )
84
84
 
85
85
 
86
- QUERY__create_account = "SELECT create_account(:username, :attach_as, :already_exists, :is_the_anonymous_user) as account_id"
86
+ QUERY__create_account = "SELECT create_account(:username, :attach_as, :already_exists, :is_the_anonymous_user, :allow_already_exists) as account_id"
87
87
  KEY__attach_as = "attach_as"
88
88
  KEY__already_exists = "already_exists"
89
+ KEY__allow_already_exists = "allow_already_exists"
89
90
  KEY__username = "username"
90
91
  KEY__is_the_anonymous_user = "is_the_anonymous_user"
91
92
  KEY__account_id = "account_id"
@@ -93,14 +94,16 @@ KEY__account_id = "account_id"
93
94
 
94
95
  def create_account(
95
96
  connection: DBInterface, encryption_key: bytes, vault_repeatable_salt: str,
96
- username, attach_as=None, already_exists=False, is_the_anonymous_user=False
97
+ username, attach_as=None, already_exists=False, is_the_anonymous_user=False,
98
+ allow_already_exists=False
97
99
  ):
98
100
  return execute_supplied_statement_singleton(
99
101
  connection, QUERY__create_account, {
100
102
  KEY__username: username,
101
103
  KEY__attach_as: attach_as,
102
104
  KEY__already_exists: already_exists,
103
- KEY__is_the_anonymous_user: is_the_anonymous_user
105
+ KEY__is_the_anonymous_user: is_the_anonymous_user,
106
+ KEY__allow_already_exists: allow_already_exists
104
107
  }, encryption_salts={
105
108
  KG__account__username: get_repeatable_salt(vault_repeatable_salt)
106
109
  }, as_objects=True, encryption_key=encryption_key, encrypt_parameters=[KG__account__username]
@@ -1,5 +1,5 @@
1
1
  """
2
- This script was generated from jaaql.fxli at 09/05/2023, 23:01:02
2
+ This script was generated from jaaql.fxli at 2024-02-11, 00:36:29
3
3
  """
4
4
 
5
5
  from jaaql.db.db_interface import DBInterface
@@ -453,6 +453,7 @@ KG__email_template__name = "name"
453
453
  KG__email_template__type = "type"
454
454
  KG__email_template__content_url = "content_url"
455
455
  KG__email_template__validation_schema = "validation_schema"
456
+ KG__email_template__dbms_user_column_name = "dbms_user_column_name"
456
457
  KG__email_template__data_validation_table = "data_validation_table"
457
458
  KG__email_template__data_validation_view = "data_validation_view"
458
459
  KG__email_template__dispatcher_domain_recipient = "dispatcher_domain_recipient"
@@ -463,12 +464,12 @@ QG__email_template_delete = "DELETE FROM email_template WHERE application = :app
463
464
  QG__email_template_insert = """
464
465
  INSERT INTO email_template (application, dispatcher, name,
465
466
  type, content_url, validation_schema,
466
- data_validation_table, data_validation_view, dispatcher_domain_recipient,
467
- can_be_sent_anonymously)
467
+ dbms_user_column_name, data_validation_table, data_validation_view,
468
+ dispatcher_domain_recipient, can_be_sent_anonymously)
468
469
  VALUES (:application, :dispatcher, :name,
469
470
  :type, :content_url, :validation_schema,
470
- :data_validation_table, :data_validation_view, :dispatcher_domain_recipient,
471
- :can_be_sent_anonymously)
471
+ :dbms_user_column_name, :data_validation_table, :data_validation_view,
472
+ :dispatcher_domain_recipient, :can_be_sent_anonymously)
472
473
  """
473
474
  QG__email_template_select_all = "SELECT * FROM email_template"
474
475
  QG__email_template_select = "SELECT * FROM email_template WHERE application = :application AND name = :name"
@@ -480,6 +481,7 @@ QG__email_template_update = """
480
481
  type = COALESCE(:type, type),
481
482
  content_url = COALESCE(:content_url, content_url),
482
483
  validation_schema = COALESCE(:validation_schema, validation_schema),
484
+ dbms_user_column_name = COALESCE(:dbms_user_column_name, dbms_user_column_name),
483
485
  data_validation_table = COALESCE(:data_validation_table, data_validation_table),
484
486
  data_validation_view = COALESCE(:data_validation_view, data_validation_view),
485
487
  dispatcher_domain_recipient = COALESCE(:dispatcher_domain_recipient, dispatcher_domain_recipient),
@@ -508,8 +510,8 @@ def email_template__update(
508
510
  connection: DBInterface,
509
511
  application, name,
510
512
  dispatcher=None, type=None, content_url=None,
511
- validation_schema=None, data_validation_table=None, data_validation_view=None,
512
- dispatcher_domain_recipient=None, can_be_sent_anonymously=None
513
+ validation_schema=None, dbms_user_column_name=None, data_validation_table=None,
514
+ data_validation_view=None, dispatcher_domain_recipient=None, can_be_sent_anonymously=None
513
515
  ):
514
516
  execute_supplied_statement(
515
517
  connection, QG__email_template_update,
@@ -523,6 +525,7 @@ def email_template__update(
523
525
  KG__email_template__type: type,
524
526
  KG__email_template__content_url: content_url,
525
527
  KG__email_template__validation_schema: validation_schema,
528
+ KG__email_template__dbms_user_column_name: dbms_user_column_name,
526
529
  KG__email_template__data_validation_table: data_validation_table,
527
530
  KG__email_template__data_validation_view: data_validation_view,
528
531
  KG__email_template__dispatcher_domain_recipient: dispatcher_domain_recipient,
@@ -560,8 +563,8 @@ def email_template__insert(
560
563
  connection: DBInterface,
561
564
  application, dispatcher, name,
562
565
  type, content_url,
563
- validation_schema=None, data_validation_table=None, data_validation_view=None,
564
- dispatcher_domain_recipient=None, can_be_sent_anonymously=None
566
+ validation_schema=None, dbms_user_column_name=None, data_validation_table=None,
567
+ data_validation_view=None, dispatcher_domain_recipient=None, can_be_sent_anonymously=None
565
568
  ):
566
569
  execute_supplied_statement(
567
570
  connection, QG__email_template_insert,
@@ -572,6 +575,7 @@ def email_template__insert(
572
575
  KG__email_template__type: type,
573
576
  KG__email_template__content_url: content_url,
574
577
  KG__email_template__validation_schema: validation_schema,
578
+ KG__email_template__dbms_user_column_name: dbms_user_column_name,
575
579
  KG__email_template__data_validation_table: data_validation_table,
576
580
  KG__email_template__data_validation_view: data_validation_view,
577
581
  KG__email_template__dispatcher_domain_recipient: dispatcher_domain_recipient,
@@ -93,8 +93,6 @@ SIGNUP__started = 1
93
93
  SIGNUP__already_registered = 2
94
94
  SIGNUP__completed = 3
95
95
 
96
- SPECIAL_COLUMN_DBMS_USER = "dbms_user"
97
-
98
96
 
99
97
  class JAAQLModel(BaseJAAQLModel):
100
98
  VERIFICATION_QUEUE = None
@@ -106,16 +104,24 @@ class JAAQLModel(BaseJAAQLModel):
106
104
  raise HttpStatusException("Not yet implemented", response_code=HTTPStatus.NOT_IMPLEMENTED)
107
105
 
108
106
  def create_account_with_potential_password(self, connection: DBInterface, username: str, attach_as: str = None, password: str = None,
109
- already_exists: bool = False, is_the_anonymous_user: bool = False):
107
+ already_exists: bool = False, is_the_anonymous_user: bool = False, allow_already_exists: bool = False):
110
108
  account_id = create_account(connection, self.get_db_crypt_key(), self.get_vault_repeatable_salt(),
111
109
  username, attach_as, already_exists,
112
- is_the_anonymous_user)
110
+ is_the_anonymous_user, allow_already_exists)
113
111
 
114
- if password:
112
+ if password and account_id != "account_already_existed":
115
113
  self.add_account_password(account_id, password)
116
114
 
115
+ if account_id == "account_already_existed":
116
+ account_id = attach_as
117
+
117
118
  return account_id
118
119
 
120
+ def create_account_batch_with_potential_password(self, connection: DBInterface, accounts: list):
121
+ for cur_input in accounts:
122
+ self.create_account_with_potential_password(connection, cur_input[KEY__username], cur_input[KEY__attach_as], cur_input[KEY__password],
123
+ allow_already_exists=True)
124
+
119
125
  def validate_query(self, queries: list, query, allow_list=True):
120
126
  if isinstance(query, list) and allow_list:
121
127
  for sub_query in query:
@@ -328,15 +334,15 @@ WHERE
328
334
  if self.is_container:
329
335
  if not self.vault.get_obj(VAULT_KEY__allow_jaaql_uninstall):
330
336
  raise HttpStatusException("JAAQL not permitted to uninstall itself")
331
-
337
+ DBPGInterface.close_all_pools()
332
338
  subprocess.call("./pg_reboot.sh", cwd="/")
333
339
  else:
334
340
  subprocess.call("docker kill jaaql_pg")
335
341
  subprocess.call("docker rm jaaql_pg")
336
342
  subprocess.Popen("docker run --name jaaql_pg -p 5434:5432 jaaql/jaaql_pg", start_new_session=True, creationflags=0x00000008)
337
343
  time.sleep(7.5)
344
+ DBPGInterface.close_all_pools()
338
345
 
339
- DBPGInterface.close_all_pools()
340
346
  self.jaaql_lookup_connection = None
341
347
  self.install_key = str(uuid.uuid4())
342
348
  self.install(
@@ -637,20 +643,23 @@ WHERE
637
643
 
638
644
  self.mark_security_event_unlocked(sec_evt)
639
645
 
640
- if template[KG__email_template__type] == EMAIL_TYPE__signup:
641
- data_relation = template[KG__email_template__data_validation_view]
642
- submit_data = {
643
- KEY__schema: template[KG__email_template__validation_schema],
644
- KEY__application: template[KEY__application],
645
- KEY_parameters: {
646
- "signed_up_at": datetime.now(),
647
- "dbms_user": sec_evt[KG__security_event__account]
648
- },
649
- KEY_query: f'UPDATE {data_relation} SET signed_up_at = :signed_up_at WHERE dbms_user = :dbms_user AND signed_up_at is null' # Ignore pycharm PEP issue
650
- }
651
- # We now get the data that can be shown in the email
652
- submit(self.vault, self.config, self.get_db_crypt_key(), self.jaaql_lookup_connection, submit_data,
653
- self.jaaql_lookup_connection.role, None, self.cached_canned_query_service)
646
+ # TODO maybe someday we'll add this back in
647
+ # if template[KG__email_template__type] == EMAIL_TYPE__signup:
648
+ # data_relation = template[KG__email_template__data_validation_view]
649
+ # dbms_user_column_name = template[KG__email_template__dbms_user_column_name]
650
+ # submit_data = {
651
+ # KEY__schema: template[KG__email_template__validation_schema],
652
+ # KEY__application: template[KEY__application],
653
+ # KEY_parameters: {
654
+ # "signed_up_at": datetime.now(),
655
+ # dbms_user_column_name: sec_evt[KG__security_event__account]
656
+ # },
657
+ # KEY_query: f'UPDATE {data_relation} SET signed_up_at = :signed_up_at WHERE {dbms_user_column_name} = :{dbms_user_column_name} AND signed_up_at is null'
658
+ # # Ignore pycharm PEP issue
659
+ # }
660
+ # # We now get the data that can be shown in the email
661
+ # submit(self.vault, self.config, self.get_db_crypt_key(), self.jaaql_lookup_connection, submit_data,
662
+ # self.jaaql_lookup_connection.role, None, self.cached_canned_query_service)
654
663
 
655
664
  return {
656
665
  KEY__parameters: parameters,
@@ -715,7 +724,10 @@ WHERE
715
724
  attachments=attachments, attachment_access_token=auth_token,
716
725
  attachment_base_url=attachment_base_url)
717
726
 
718
- def reset_password(self, inputs: dict):
727
+ def reset_password(self, inputs: dict, is_the_anonymous_user: bool):
728
+ if is_the_anonymous_user:
729
+ raise HttpStatusException("Cannot change this user's password")
730
+
719
731
  app = application__select(self.jaaql_lookup_connection, inputs[KG__security_event__application])
720
732
  if inputs[KEY__reset_password_template] is None:
721
733
  inputs[KEY__reset_password_template] = app[KG__application__default_r_et]
@@ -785,8 +797,9 @@ WHERE
785
797
  KG__security_event__event_lock: reg_env_ins[KG__security_event__event_lock]
786
798
  }
787
799
 
788
- def sign_up(self, inputs: dict, account_id: str):
800
+ def sign_up(self, inputs: dict, account_id: str, is_the_anonymous_user: bool):
789
801
  app = application__select(self.jaaql_lookup_connection, inputs[KG__security_event__application])
802
+
790
803
  if inputs[KEY__sign_up_template] is None:
791
804
  inputs[KEY__sign_up_template] = app[KG__application__default_s_et]
792
805
  if inputs[KEY__already_signed_up_template] is None:
@@ -803,11 +816,17 @@ WHERE
803
816
  if sign_up_template[KG__email_template__type] != EMAIL_TYPE__signup:
804
817
  raise HttpStatusException(ERR__template_not_signup)
805
818
 
819
+ dbms_user_column_name = sign_up_template[KG__email_template__dbms_user_column_name]
820
+
806
821
  already_signed_up_template = email_template__select(self.jaaql_lookup_connection, inputs[KG__security_event__application],
807
822
  inputs[KEY__already_signed_up_template])
808
823
  if already_signed_up_template[KG__email_template__type] != EMAIL_TYPE__already_signed_up:
809
824
  raise HttpStatusException(ERR__template_not_already)
810
825
 
826
+ if is_the_anonymous_user and (not already_signed_up_template[KG__email_template__can_be_sent_anonymously] or
827
+ not sign_up_template[KG__email_template__can_be_sent_anonymously]):
828
+ raise HttpStatusException("Cannot sign up publicly using this route")
829
+
811
830
  conn = None
812
831
  account_db_interface = None
813
832
 
@@ -825,17 +844,16 @@ WHERE
825
844
  ret = submit(self.vault, self.config, self.get_db_crypt_key(), self.jaaql_lookup_connection, submit_data, account_id, None,
826
845
  self.cached_canned_query_service, as_objects=False, singleton=True, keep_alive_conn=True, conn=conn, interface=account_db_interface)
827
846
  ret = objectify(ret[list(ret.keys())[-1]], singleton=True)
828
-
829
847
  # This is the permissions check. It is an update that returns something that is ignored
830
848
  # An exception will be triggered here if the user does not have permissions
831
849
  where_clause = " AND ".join(['"' + key + '" = :' + key for key in ret.keys() if re.match(REGEX__dmbs_object_name, key) is not None])
832
850
  if len(where_clause) != 0:
833
851
  where_clause = " AND " + where_clause
834
852
  sign_up_table = sign_up_template[KG__email_template__data_validation_table]
835
- upt_query = f'UPDATE "{sign_up_table}" SET dbms_user = :dbms_user WHERE dbms_user is null{where_clause}' # Ignore pycharm pep issue
853
+ upt_query = f'UPDATE "{sign_up_table}" SET "{dbms_user_column_name}" = :{dbms_user_column_name} WHERE {dbms_user_column_name} is null{where_clause}' # Ignore pycharm pep issue
836
854
  submit_data[KEY_query] = upt_query
837
855
  submit_data[KEY_parameters] = ret
838
- submit_data[KEY_parameters][SPECIAL_COLUMN_DBMS_USER] = None
856
+ submit_data[KEY_parameters][dbms_user_column_name] = None
839
857
  submit(self.vault, self.config, self.get_db_crypt_key(), self.jaaql_lookup_connection, submit_data, account_id,
840
858
  None, self.cached_canned_query_service, keep_alive_conn=True, conn=conn, interface=account_db_interface)
841
859
 
@@ -848,7 +866,7 @@ WHERE
848
866
  KEY__application: inputs[KG__security_event__application],
849
867
  KEY__schema: sign_up_template[KG__email_template__validation_schema],
850
868
  KEY_parameters: inputs[KEY__parameters],
851
- KEY_query: f'SELECT dbms_user FROM {data_relation} WHERE {where_clause[5:]}' # Ignore pycharm PEP issue
869
+ KEY_query: f'SELECT {dbms_user_column_name} FROM {data_relation} WHERE {where_clause[5:]}' # Ignore pycharm PEP issue
852
870
  }
853
871
 
854
872
  try:
@@ -856,7 +874,7 @@ WHERE
856
874
  self.jaaql_lookup_connection, get_user_data,
857
875
  self.jaaql_lookup_connection.role, None,
858
876
  self.cached_canned_query_service, as_objects=True,
859
- singleton=True)["dbms_user"]
877
+ singleton=True)[dbms_user_column_name]
860
878
 
861
879
  account = account__select(self.jaaql_lookup_connection, self.get_db_crypt_key(), dbms_user)
862
880
  inputs[KEY__username] = account[KG__account__username]
@@ -879,7 +897,7 @@ WHERE
879
897
 
880
898
  # We set the dbms user in the application. This can potentially cause an index clash due to a unique index on the dbms_user column
881
899
  # This is desirable in many situations but will allow username enumeration
882
- submit_data[KEY__parameters][SPECIAL_COLUMN_DBMS_USER] = new_account_id
900
+ submit_data[KEY__parameters][dbms_user_column_name] = new_account_id
883
901
  submit(self.vault, self.config, self.get_db_crypt_key(), self.jaaql_lookup_connection, submit_data, account_id,
884
902
  None, self.cached_canned_query_service, keep_alive_conn=True, conn=conn, interface=account_db_interface)
885
903
 
@@ -903,11 +921,16 @@ WHERE
903
921
  # We will change the model in the future when time allows that we have a single sign up and reset template with alternatives attached
904
922
  if re.match(REGEX__dmbs_object_name, data_relation) is None:
905
923
  raise HttpStatusException("Unsafe data relation specified for sign up")
906
- submit_data[KEY_query] = f'SELECT * FROM {data_relation} WHERE dbms_user = :dbms_user{where_clause}' # Ignore pycharm PEP issue
924
+ submit_data[KEY_query] = f'SELECT * FROM {data_relation} WHERE "{dbms_user_column_name}" = :{dbms_user_column_name}{where_clause}' # Ignore pycharm PEP issue
907
925
  # We now get the data that can be shown in the email
908
- email_replacement_data = submit(self.vault, self.config, self.get_db_crypt_key(), self.jaaql_lookup_connection, submit_data,
909
- self.jaaql_lookup_connection.role, None, self.cached_canned_query_service, as_objects=True,
910
- singleton=True)
926
+ try:
927
+ email_replacement_data = submit(self.vault, self.config, self.get_db_crypt_key(), self.jaaql_lookup_connection, submit_data,
928
+ self.jaaql_lookup_connection.role, None, self.cached_canned_query_service, as_objects=True,
929
+ singleton=True)
930
+ except HttpSingletonStatusException:
931
+ del submit_data[KEY__parameters][dbms_user_column_name]
932
+ raise HttpSingletonStatusException(f'Unable to locate email data. Please check that the data returned from your input query (do _not_ include {
933
+ dbms_user_column_name}) matches an entry in {data_relation}: ' + json.dumps(submit_data, indent=4))
911
934
 
912
935
  template = already_signed_up_template if account_existed else sign_up_template
913
936
  unlock_code = self.gen_security_event_unlock_code(CODE__letters, CODE__invite_length)
@@ -144,7 +144,7 @@ TYPE__exceptions = Optional[Union[List[SwaggerResponseException], SwaggerRespons
144
144
  class SwaggerSimpleList:
145
145
 
146
146
  def __init__(self, arg_type: type, description: str, example: Optional[TYPE__example] = None,
147
- required: bool = False, condition: str = None):
147
+ required: bool = True, condition: str = None):
148
148
  self.arg_type = arg_type
149
149
  self.description = description
150
150
  self.example = example
@@ -11,16 +11,16 @@ CREATE DOMAIN internet_name AS character varying(63) CHECK (VALUE ~* '^[a-z0-9\-
11
11
  CREATE DOMAIN url AS character varying(256);
12
12
  CREATE DOMAIN location AS character varying(256);
13
13
  CREATE DOMAIN object_name AS character varying(63) CHECK (VALUE ~* '^[a-z0-9_]*$');
14
- CREATE DOMAIN validity_period AS integer;
15
- CREATE DOMAIN short_validity_period AS integer;
14
+ CREATE DOMAIN validity_period AS integer CHECK (VALUE between 15 and 9999999);
15
+ CREATE DOMAIN short_validity_period AS integer CHECK (VALUE between 15 and 86400);
16
16
  CREATE DOMAIN person_name AS character varying(64);
17
17
  CREATE DOMAIN email_dispatch_protocol AS character varying(8);
18
- CREATE DOMAIN internet_port AS integer;
18
+ CREATE DOMAIN internet_port AS integer CHECK (VALUE between 1 and 65536);
19
19
  CREATE DOMAIN email_server_username AS character varying(255);
20
20
  CREATE DOMAIN postgres_role AS character varying(63);
21
- CREATE DOMAIN attempt_count AS smallint;
21
+ CREATE DOMAIN attempt_count AS smallint CHECK (VALUE between 1 and 3);
22
22
  CREATE DOMAIN email_template_type AS character varying(1);
23
23
  CREATE DOMAIN safe_path AS character varying(255) CHECK (VALUE ~* '^[a-z$0-9_\-\/]+(\.[a-zA-Z0-9]+)?$');
24
24
  CREATE DOMAIN email_account_username AS character varying(64) CHECK (VALUE ~* '^[a-zA-Z0-9_\-\.]+$');
25
- CREATE DOMAIN current_attempt_count AS smallint;
25
+ CREATE DOMAIN current_attempt_count AS smallint CHECK (VALUE between 0 and 3);
26
26
  CREATE DOMAIN unlock_code AS character varying(10);
@@ -1,11 +1,18 @@
1
- create function create_account(username text, attach_as postgres_role = null, already_exists boolean = false, is_the_anonymous_user boolean = false) returns postgres_role as
1
+ create function create_account(username text, attach_as postgres_role = null, already_exists boolean = false, is_the_anonymous_user boolean = false, allow_already_exists boolean = false) returns postgres_role as
2
2
  $$
3
3
  DECLARE
4
4
  account_id postgres_role;
5
5
  BEGIN
6
6
  if attach_as is not null then
7
7
  if not already_exists then
8
- EXECUTE 'CREATE ROLE ' || quote_ident(attach_as);
8
+ BEGIN
9
+ EXECUTE 'CREATE ROLE ' || quote_ident(attach_as);
10
+ EXCEPTION WHEN duplicate_object THEN
11
+ IF NOT allow_already_exists THEN
12
+ RAISE;
13
+ END IF;
14
+ return 'account_already_existed';
15
+ END;
9
16
  end if;
10
17
  INSERT INTO account (id, username) VALUES (attach_as, create_account.username) RETURNING id INTO account_id;
11
18
  else