@verii/endpoints-organizations-registrar 1.0.0-pre.1752076816

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 (259) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +1 -0
  3. package/README.md +3 -0
  4. package/package.json +86 -0
  5. package/src/config/abi.json +1 -0
  6. package/src/config/config.js +261 -0
  7. package/src/controllers/consents/autohooks.js +6 -0
  8. package/src/controllers/consents/controller.js +106 -0
  9. package/src/controllers/consents/schemas/consent-response.schema.js +45 -0
  10. package/src/controllers/did-web-host/controller.js +64 -0
  11. package/src/controllers/groups/autohooks.js +10 -0
  12. package/src/controllers/groups/controller.js +172 -0
  13. package/src/controllers/groups/schemas/group.schema.json +22 -0
  14. package/src/controllers/groups/schemas/index.js +7 -0
  15. package/src/controllers/groups/schemas/modify-group.schema.json +25 -0
  16. package/src/controllers/image_upload/controller.js +48 -0
  17. package/src/controllers/invitations/controller.js +79 -0
  18. package/src/controllers/organizations/_did/autohooks.js +16 -0
  19. package/src/controllers/organizations/_did/controller.js +617 -0
  20. package/src/controllers/organizations/_did/invitations/_invitationId/autohooks.js +16 -0
  21. package/src/controllers/organizations/_did/invitations/_invitationId/controller.js +217 -0
  22. package/src/controllers/organizations/_did/invitations/controller.js +197 -0
  23. package/src/controllers/organizations/_did/keys/controller.js +141 -0
  24. package/src/controllers/organizations/_did/services/controller.js +195 -0
  25. package/src/controllers/organizations/_did/signatories/controller.js +63 -0
  26. package/src/controllers/organizations/autohooks.js +65 -0
  27. package/src/controllers/organizations/controller.js +322 -0
  28. package/src/controllers/organizations/full/controller.js +285 -0
  29. package/src/controllers/organizations/plugins.js +21 -0
  30. package/src/controllers/organizations/schemas/add-key-body.schema.json +35 -0
  31. package/src/controllers/organizations/schemas/create-did-service.schema.json +70 -0
  32. package/src/controllers/organizations/schemas/did-key.schema.json +178 -0
  33. package/src/controllers/organizations/schemas/full-organization.schema.json +35 -0
  34. package/src/controllers/organizations/schemas/index.js +33 -0
  35. package/src/controllers/organizations/schemas/invitationCodeProperty.schema.json +3 -0
  36. package/src/controllers/organizations/schemas/organization-ids.schema.json +34 -0
  37. package/src/controllers/organizations/schemas/organization-kyb-profile-creation.schema.json +26 -0
  38. package/src/controllers/organizations/schemas/organization-profile-creation.schema.json +20 -0
  39. package/src/controllers/organizations/schemas/organization-profile-update.schema.json +19 -0
  40. package/src/controllers/organizations/schemas/organization-profile-verifiable-credential.schema.json +25 -0
  41. package/src/controllers/organizations/schemas/organization-registry-service-response.schema.json +26 -0
  42. package/src/controllers/organizations/schemas/organization-service.schema.json +34 -0
  43. package/src/controllers/organizations/schemas/organization-verified-profile.schema.json +123 -0
  44. package/src/controllers/organizations/schemas/organization.search-profile.query-params.schema.json +50 -0
  45. package/src/controllers/organizations/schemas/organization.search.query-params.schema.json +42 -0
  46. package/src/controllers/reference/controller.js +103 -0
  47. package/src/controllers/resolve-did/controller.js +45 -0
  48. package/src/controllers/resolve-did/resolve-did.js +30 -0
  49. package/src/controllers/resolve-did/schemas/did-doc.schema.json +155 -0
  50. package/src/controllers/resolve-did/schemas/did-proof.schema.json +44 -0
  51. package/src/controllers/resolve-did/schemas/index.js +26 -0
  52. package/src/controllers/resolve-did/schemas/public-key.schema.json +173 -0
  53. package/src/controllers/resolve-kid/controller.js +76 -0
  54. package/src/controllers/resolve-kid/public-key-formats.js +8 -0
  55. package/src/controllers/service-types/controller.js +81 -0
  56. package/src/controllers/setup_image_upload/controller.js +99 -0
  57. package/src/controllers/signatories/controller.js +43 -0
  58. package/src/controllers/users/autohooks.js +10 -0
  59. package/src/controllers/users/controller.js +221 -0
  60. package/src/controllers/users/schemas/base-user.schema.json +55 -0
  61. package/src/controllers/users/schemas/index.js +4 -0
  62. package/src/controllers/users/schemas/modify-user.schema.js +17 -0
  63. package/src/controllers/users/schemas/user.schema.js +20 -0
  64. package/src/entities/groups/domain/constants.js +21 -0
  65. package/src/entities/groups/domain/index.js +19 -0
  66. package/src/entities/groups/factories/groups-factory.js +48 -0
  67. package/src/entities/groups/factories/index.js +17 -0
  68. package/src/entities/groups/index.js +19 -0
  69. package/src/entities/groups/repo.js +122 -0
  70. package/src/entities/images/domain/constant.js +11 -0
  71. package/src/entities/images/domain/index.js +3 -0
  72. package/src/entities/images/extension/activate.extension.js +35 -0
  73. package/src/entities/images/extension/deactivate.extension.js +27 -0
  74. package/src/entities/images/extension/find-by-url.extension.js +24 -0
  75. package/src/entities/images/extension/index.js +5 -0
  76. package/src/entities/images/factories/images-factory.js +43 -0
  77. package/src/entities/images/factories/index.js +17 -0
  78. package/src/entities/images/index.js +5 -0
  79. package/src/entities/images/repo.js +43 -0
  80. package/src/entities/images/schema/image-metadata.schema.js +58 -0
  81. package/src/entities/images/schema/index.js +3 -0
  82. package/src/entities/index.js +31 -0
  83. package/src/entities/invitations/domains/build-invitation-url.js +14 -0
  84. package/src/entities/invitations/domains/get-given-family-name-from-name.js +20 -0
  85. package/src/entities/invitations/domains/index.js +7 -0
  86. package/src/entities/invitations/domains/init-invitation-emails.js +17 -0
  87. package/src/entities/invitations/domains/is-invitation-expired.js +5 -0
  88. package/src/entities/invitations/domains/validate-invitee-email.js +18 -0
  89. package/src/entities/invitations/factories/index.js +17 -0
  90. package/src/entities/invitations/factories/invitations-factory.js +51 -0
  91. package/src/entities/invitations/index.js +6 -0
  92. package/src/entities/invitations/orchestrators/accept-invitation.js +24 -0
  93. package/src/entities/invitations/orchestrators/index.js +4 -0
  94. package/src/entities/invitations/orchestrators/send-email-invitee.js +36 -0
  95. package/src/entities/invitations/repo.js +37 -0
  96. package/src/entities/invitations/schemas/add-invitation-body.js +122 -0
  97. package/src/entities/invitations/schemas/get-invitation-response-body.js +20 -0
  98. package/src/entities/invitations/schemas/index.js +5 -0
  99. package/src/entities/invitations/schemas/invitation-response-item-body.js +61 -0
  100. package/src/entities/kms/factories/index.js +17 -0
  101. package/src/entities/kms/factories/kms-factory.js +31 -0
  102. package/src/entities/monitors/index.js +17 -0
  103. package/src/entities/monitors/orchestrators/index.js +17 -0
  104. package/src/entities/monitors/orchestrators/monitors.js +230 -0
  105. package/src/entities/oauth/domain/constants.js +23 -0
  106. package/src/entities/oauth/domain/index.js +5 -0
  107. package/src/entities/oauth/domain/roles.js +92 -0
  108. package/src/entities/oauth/domain/scopes.js +35 -0
  109. package/src/entities/oauth/index.js +4 -0
  110. package/src/entities/oauth/orchestrators/auth0-provisioner.js +293 -0
  111. package/src/entities/oauth/orchestrators/index.js +3 -0
  112. package/src/entities/organization-keys/domains/build-organization-key.js +50 -0
  113. package/src/entities/organization-keys/domains/constants.js +30 -0
  114. package/src/entities/organization-keys/domains/extract-verification-method-from-byo-did-document.js +38 -0
  115. package/src/entities/organization-keys/domains/find-key-by-purpose.js +6 -0
  116. package/src/entities/organization-keys/domains/index.js +10 -0
  117. package/src/entities/organization-keys/domains/jwk-to-hex-key-transformer.js +13 -0
  118. package/src/entities/organization-keys/domains/map-key-response.js +29 -0
  119. package/src/entities/organization-keys/domains/validate-non-custodial-key.js +11 -0
  120. package/src/entities/organization-keys/domains/validate-organization-key.js +42 -0
  121. package/src/entities/organization-keys/factories/index.js +17 -0
  122. package/src/entities/organization-keys/factories/organization-keys-factory.js +55 -0
  123. package/src/entities/organization-keys/index.js +5 -0
  124. package/src/entities/organization-keys/orchestrators/add-key-to-did-doc.js +19 -0
  125. package/src/entities/organization-keys/orchestrators/add-key.js +155 -0
  126. package/src/entities/organization-keys/orchestrators/add-operator-keys.js +46 -0
  127. package/src/entities/organization-keys/orchestrators/delete-key.js +93 -0
  128. package/src/entities/organization-keys/orchestrators/get-key.js +39 -0
  129. package/src/entities/organization-keys/orchestrators/index.js +24 -0
  130. package/src/entities/organization-keys/orchestrators/resolve-verification-method-byo-did.js +28 -0
  131. package/src/entities/organization-keys/repos/repo.js +48 -0
  132. package/src/entities/organization-services/adapters/index.js +21 -0
  133. package/src/entities/organization-services/adapters/init-provision-auth0-client-grants.js +44 -0
  134. package/src/entities/organization-services/adapters/init-provision-auth0-clients.js +56 -0
  135. package/src/entities/organization-services/adapters/update-blockchain-permissions-from-permitted-services.js +118 -0
  136. package/src/entities/organization-services/domains/activate-services.js +12 -0
  137. package/src/entities/organization-services/domains/build-organizations-services.js +38 -0
  138. package/src/entities/organization-services/domains/build-public-services.js +19 -0
  139. package/src/entities/organization-services/domains/constants.js +32 -0
  140. package/src/entities/organization-services/domains/extract-cao-service-refs.js +10 -0
  141. package/src/entities/organization-services/domains/extract-service-endpoint-did.js +10 -0
  142. package/src/entities/organization-services/domains/get-service-consent-type.js +16 -0
  143. package/src/entities/organization-services/domains/get-service-types-from-categories.js +18 -0
  144. package/src/entities/organization-services/domains/index.js +17 -0
  145. package/src/entities/organization-services/domains/is-new-node-operator-service.js +25 -0
  146. package/src/entities/organization-services/domains/is-service-category.js +31 -0
  147. package/src/entities/organization-services/domains/normalize-service-endpoint.js +6 -0
  148. package/src/entities/organization-services/domains/select-activated-services.js +8 -0
  149. package/src/entities/organization-services/domains/transform-profile-service.js +88 -0
  150. package/src/entities/organization-services/domains/validate-cao-service-refs.js +25 -0
  151. package/src/entities/organization-services/domains/validate-service-credential-type.js +47 -0
  152. package/src/entities/organization-services/domains/validate-service-endpoint.js +35 -0
  153. package/src/entities/organization-services/domains/validate-service-fields-by-service-type.js +37 -0
  154. package/src/entities/organization-services/domains/validate-service-id-uniqueness.js +19 -0
  155. package/src/entities/organization-services/domains/validate-service-key-purposes.js +56 -0
  156. package/src/entities/organization-services/domains/validate-service-type.js +12 -0
  157. package/src/entities/organization-services/domains/validate-service.js +80 -0
  158. package/src/entities/organization-services/domains/validate-services-for-delete.js +32 -0
  159. package/src/entities/organization-services/index.js +5 -0
  160. package/src/entities/organization-services/orchestrators/add-service.js +106 -0
  161. package/src/entities/organization-services/orchestrators/delete-service.js +142 -0
  162. package/src/entities/organization-services/orchestrators/get-service.js +36 -0
  163. package/src/entities/organization-services/orchestrators/index.js +8 -0
  164. package/src/entities/organization-services/orchestrators/init-add-service-to-organization.js +141 -0
  165. package/src/entities/organization-services/orchestrators/load-cao-service-refs.js +56 -0
  166. package/src/entities/organization-services/orchestrators/update-service.js +103 -0
  167. package/src/entities/organizations/adapters/index.js +6 -0
  168. package/src/entities/organizations/adapters/init-organization-registrar-emails.js +215 -0
  169. package/src/entities/organizations/adapters/init-send-activation-emails-to-caos.js +89 -0
  170. package/src/entities/organizations/adapters/send-email-invitation-accepted-to-inviter.js +70 -0
  171. package/src/entities/organizations/adapters/send-email-notifications.js +212 -0
  172. package/src/entities/organizations/domains/build-custodied-did-web.js +12 -0
  173. package/src/entities/organizations/domains/build-full-organization-response.js +40 -0
  174. package/src/entities/organizations/domains/build-organization-modifications-on-service-change.js +82 -0
  175. package/src/entities/organizations/domains/build-profile-vc-url.js +8 -0
  176. package/src/entities/organizations/domains/build-profile-verifiable-credential.js +36 -0
  177. package/src/entities/organizations/domains/build-public-profile.js +9 -0
  178. package/src/entities/organizations/domains/constants.js +54 -0
  179. package/src/entities/organizations/domains/index.js +17 -0
  180. package/src/entities/organizations/domains/organization-vc-checks.js +49 -0
  181. package/src/entities/organizations/domains/parse-profile-to-csv.js +41 -0
  182. package/src/entities/organizations/domains/prepare-profile-vc.js +28 -0
  183. package/src/entities/organizations/domains/profile-name-normalization.js +5 -0
  184. package/src/entities/organizations/domains/validate-byo-did-keys.js +28 -0
  185. package/src/entities/organizations/domains/validate-profile-name.js +48 -0
  186. package/src/entities/organizations/domains/validate-profile-website.js +17 -0
  187. package/src/entities/organizations/domains/validate-update-profile.js +11 -0
  188. package/src/entities/organizations/factories/index.js +17 -0
  189. package/src/entities/organizations/factories/organizations-factory.js +180 -0
  190. package/src/entities/organizations/index.js +6 -0
  191. package/src/entities/organizations/orchestrators/add-primary-permissions.js +28 -0
  192. package/src/entities/organizations/orchestrators/build-custodied-organization.js +92 -0
  193. package/src/entities/organizations/orchestrators/build-non-custodied-organization.js +83 -0
  194. package/src/entities/organizations/orchestrators/index.js +6 -0
  195. package/src/entities/organizations/orchestrators/init-create-organization.js +221 -0
  196. package/src/entities/organizations/orchestrators/init-provision-group.js +48 -0
  197. package/src/entities/organizations/orchestrators/verify-profile-website-unique.js +15 -0
  198. package/src/entities/organizations/repos/find-caos-extension.js +49 -0
  199. package/src/entities/organizations/repos/index.js +17 -0
  200. package/src/entities/organizations/repos/repo.js +156 -0
  201. package/src/entities/organizations/repos/search-by-aggregation-extension.js +128 -0
  202. package/src/entities/organizations/repos/transform-did-filter.js +13 -0
  203. package/src/entities/organizations/repos/transform-organization-filter.js +106 -0
  204. package/src/entities/registrar-consents/constants.js +10 -0
  205. package/src/entities/registrar-consents/factories/index.js +17 -0
  206. package/src/entities/registrar-consents/factories/registrar-consents-factory.js +38 -0
  207. package/src/entities/registrar-consents/index.js +3 -0
  208. package/src/entities/registrar-consents/repos/registrar-consent-repo-extension.js +55 -0
  209. package/src/entities/registrar-consents/repos/repo.js +31 -0
  210. package/src/entities/signatories/domain/constants.js +12 -0
  211. package/src/entities/signatories/domain/index.js +4 -0
  212. package/src/entities/signatories/domain/organization-emails.js +29 -0
  213. package/src/entities/signatories/factories/index.js +17 -0
  214. package/src/entities/signatories/factories/signatory-status-factory.js +53 -0
  215. package/src/entities/signatories/index.js +5 -0
  216. package/src/entities/signatories/orchestrators/approve-reminder.js +24 -0
  217. package/src/entities/signatories/orchestrators/index.js +6 -0
  218. package/src/entities/signatories/orchestrators/reject-reminder.js +17 -0
  219. package/src/entities/signatories/orchestrators/send-reminders.js +102 -0
  220. package/src/entities/signatories/orchestrators/validate-auth-code.js +56 -0
  221. package/src/entities/signatories/repos/index.js +3 -0
  222. package/src/entities/signatories/repos/repo.js +35 -0
  223. package/src/entities/signatories/repos/signatory-status-state-repo-extension.js +124 -0
  224. package/src/entities/users/domains/constants.js +40 -0
  225. package/src/entities/users/domains/index.js +4 -0
  226. package/src/entities/users/domains/user-registrar-emails.js +52 -0
  227. package/src/entities/users/index.js +4 -0
  228. package/src/entities/users/orchestrators/create-auth0-user.js +60 -0
  229. package/src/entities/users/orchestrators/get-or-create-auth0-user.js +63 -0
  230. package/src/entities/users/orchestrators/index.js +22 -0
  231. package/src/entities/users/orchestrators/user-management.js +157 -0
  232. package/src/fetchers/index.js +19 -0
  233. package/src/fetchers/monitoring/index.js +9 -0
  234. package/src/fetchers/monitoring/monitor-add-to-page-fetcher.js +18 -0
  235. package/src/fetchers/monitoring/monitor-create-fetcher.js +23 -0
  236. package/src/fetchers/monitoring/monitor-delete-fetcher.js +6 -0
  237. package/src/fetchers/monitoring/monitor-get-all-fetcher.js +6 -0
  238. package/src/fetchers/monitoring/section-create-fetcher.js +16 -0
  239. package/src/fetchers/monitoring/section-get-all-fetcher.js +6 -0
  240. package/src/fetchers/monitoring/service-version-fetcher.js +6 -0
  241. package/src/helpers/init-permissions-contract.js +48 -0
  242. package/src/index.js +23 -0
  243. package/src/init-server.js +91 -0
  244. package/src/organizations-registrar-endpoints.js +68 -0
  245. package/src/plugins/authorization.js +233 -0
  246. package/src/plugins/index.js +4 -0
  247. package/src/plugins/pubsub-plugin.js +82 -0
  248. package/src/subscribers/notify-caos.js +63 -0
  249. package/src/subscribers/notify-inviters.js +42 -0
  250. package/src/subscribers/notify-monitoring.js +40 -0
  251. package/src/subscribers/notify-signatory.js +51 -0
  252. package/src/subscribers/notify-support-and-groups.js +95 -0
  253. package/src/templates/invitee-invitation-email-body.hbs +13 -0
  254. package/src/templates/invitee-invitation-email-subject.hbs +1 -0
  255. package/src/templates/signatory-approval-email-body.hbs +92 -0
  256. package/src/templates/support-organization-created-body.hbs +17 -0
  257. package/src/templates/support-organization-created-subject.hbs +1 -0
  258. package/src/templates/support-signatory-max-reminders-reached-email-body.hbs +6 -0
  259. package/src/templates/support-signatory-max-reminders-reached-email-subject.hbs +1 -0
@@ -0,0 +1,215 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { map } = require('lodash/fp');
19
+ const { buildPublicServices } = require('../../organization-services/domains');
20
+
21
+ const whichNet = ({ nodeEnv }) => {
22
+ switch (nodeEnv) {
23
+ case 'development':
24
+ case 'test':
25
+ return 'LocalDevNet';
26
+ case 'dev':
27
+ return 'DevNet';
28
+ case 'staging':
29
+ return 'TestNet';
30
+ case 'production':
31
+ return 'MainNet';
32
+ default:
33
+ return '';
34
+ }
35
+ };
36
+ const initOrganizationRegistrarEmails = (config) => {
37
+ return {
38
+ emailToNewOrgForServicesActivated: ({
39
+ organization,
40
+ activatedServiceIds = [],
41
+ emails,
42
+ }) => {
43
+ return {
44
+ subject: `Velocity Services Activated on ${whichNet(config)}`,
45
+ message: `Congratulations!
46
+ <br>
47
+ <br>
48
+ You are being contacted because you are the admin of ${
49
+ organization.profile.name
50
+ } on Velocity Network ${whichNet(
51
+ config
52
+ )} and your services were just activated!
53
+ <br>
54
+ <br>
55
+ You can now access your organization’s Payments and Rewards Hub account on ${whichNet(
56
+ config
57
+ )}.
58
+ To do so, please go <a href="${config.tokenWalletBaseUrl}/o/${
59
+ organization.didDoc.id
60
+ }">here</a> and log in with your Velocity Network Registrar admin credentials.
61
+ Please confirm that you were able to successfully log in.
62
+ <br>
63
+ <br>
64
+ Your DID is registered on the Velocity Network ${whichNet(config)} as ${
65
+ organization.didDoc.id
66
+ }.
67
+ <br>
68
+ <br>
69
+ The following services have been activated for you on Velocity Network ${whichNet(
70
+ config
71
+ )}:
72
+ <br>
73
+ <br>
74
+ ${JSON.stringify(activatedServiceIds, null, 2)}
75
+ <br>
76
+ <br>
77
+ If you have any questions or problems, please reply to this email.
78
+ <br>
79
+ <br>
80
+ Regards,
81
+ <br>
82
+ <br>
83
+ The Velocity Network Registrar
84
+ `,
85
+ sender: config.registrarSupportEmail,
86
+ recipients: emails,
87
+ replyTo: config.registrarSupportEmail,
88
+ html: true,
89
+ };
90
+ },
91
+ emailToRegisteredOrgForServicesActivated: ({
92
+ organization,
93
+ activatedServiceIds = [],
94
+ emails,
95
+ }) => ({
96
+ subject: `Velocity Services Activated on ${whichNet(config)}`,
97
+ message: `
98
+ Hello,
99
+
100
+ You are being contacted because you are the admin of ${
101
+ organization.profile.name
102
+ } on Velocity Network ${whichNet(
103
+ config
104
+ )} and a new service has just been added to your organization.
105
+
106
+ The following services have been activated for you on Velocity Network ${whichNet(
107
+ config
108
+ )}:
109
+
110
+ ${JSON.stringify(activatedServiceIds, null, 2)}
111
+
112
+ If you have any questions or problems, please reply to this email.
113
+
114
+ Regards,
115
+
116
+ The Velocity Network Registrar`,
117
+ sender: config.registrarSupportEmail,
118
+ recipients: emails,
119
+ replyTo: config.registrarSupportEmail,
120
+ }),
121
+ emailToSupportForOrgRegisteredAndServicesNeedActivation: (
122
+ { organization, addedServices = [] },
123
+ context
124
+ ) => ({
125
+ subject: `${config.nodeEnv.toUpperCase()}: Velocity Services Activation Required`,
126
+ message: `Hello,
127
+ The organization: "${organization.profile.name}" with did "${
128
+ organization.didDoc.id
129
+ }" has registered.
130
+
131
+ Their full profile looks like this:
132
+ ${JSON.stringify(organization.profile, null, 2)}
133
+
134
+ Their requested services are:
135
+ ${JSON.stringify(addedServices, null, 2)}
136
+
137
+ userAgent: ${context.headers['user-agent']}
138
+
139
+ Check in Zoho and trigger the API endpoint everything is kosher.
140
+
141
+ Regards,
142
+ BYTER-9000!
143
+ `,
144
+ sender: config.noReplyEmail,
145
+ recipients: [config.registrarSupportEmail],
146
+ }),
147
+ emailToSupportForServicesAddedAndNeedActivation: (
148
+ { organization, addedServices = [] },
149
+ context
150
+ ) => ({
151
+ subject: `${config.nodeEnv.toUpperCase()}: Velocity Services Activation Required`,
152
+ message: `Hello,
153
+ The following service(s) have been added to "${
154
+ organization.profile.name
155
+ }" with did "${organization.didDoc.id}":
156
+
157
+ ${JSON.stringify(buildPublicServices(addedServices), null, 2)}
158
+
159
+ userAgent: ${context.headers['user-agent']}
160
+
161
+ Check in Zoho and trigger the API endpoint everything is kosher.
162
+
163
+ Regards,
164
+ BYTER-9000!
165
+ `,
166
+ sender: config.noReplyEmail,
167
+ recipients: [config.registrarSupportEmail],
168
+ }),
169
+ emailToCAOsForServicesActivation: ({
170
+ organization,
171
+ activatedService,
172
+ emails,
173
+ }) => ({
174
+ subject: `${organization.profile.name} service is now active`,
175
+ message: `${organization.profile.name} has had the following service activated on the Velocity Network™:
176
+
177
+ ${activatedService.type} on the agent ${activatedService.id} at ${activatedService.serviceEndpoint}
178
+
179
+ The service is now able to be used on the Velocity Network™.
180
+ `,
181
+ sender: config.registrarSupportEmail,
182
+ recipients: emails,
183
+ replyTo: config.registrarSupportEmail,
184
+ }),
185
+ emailToGroupForInvitationAccepted: ({
186
+ organization,
187
+ services,
188
+ emails,
189
+ }) => ({
190
+ subject: `${config.nodeEnv.toUpperCase()}: ${
191
+ organization.profile.name
192
+ } has accepted your invitation`,
193
+ /* eslint-disable max-len */
194
+ message: `
195
+ ${
196
+ organization.profile.name
197
+ } has accepted your invitation to join the Velocity Network™. The following service(s) has been registered:
198
+
199
+ ${map(
200
+ (service) =>
201
+ `${service.type} on the agent ${service.caoService.id} at ${service.caoService.serviceEndpoint}`,
202
+ services
203
+ ).join(' \n')}
204
+
205
+ The service is still inactive. The foundation staff are reviewing the application and will activate the services on in the next 72 hours. Upon successful review you will receive confirmation by email.
206
+ `,
207
+ /* eslint-enable */
208
+ sender: config.registrarSupportEmail,
209
+ recipients: emails,
210
+ replyTo: config.registrarSupportEmail,
211
+ }),
212
+ };
213
+ };
214
+
215
+ module.exports = { initOrganizationRegistrarEmails };
@@ -0,0 +1,89 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { map, isEmpty } = require('lodash/fp');
19
+ const { initAuth0Provisioner } = require('../../oauth');
20
+ const {
21
+ selectActivatedServices,
22
+ } = require('../../organization-services/domains');
23
+ const {
24
+ initOrganizationRegistrarEmails,
25
+ } = require('./init-organization-registrar-emails');
26
+
27
+ const initSendActivationEmailsToCAOs = (initCtx) => {
28
+ const { sendEmail, config, sendError } = initCtx;
29
+ const { emailToCAOsForServicesActivation } =
30
+ initOrganizationRegistrarEmails(config);
31
+
32
+ const { getUsersByIds } = initAuth0Provisioner(config);
33
+
34
+ return async (
35
+ organization,
36
+ services,
37
+ serviceIds = [],
38
+ caoServiceRefs,
39
+ context
40
+ ) => {
41
+ const { repos, log } = context;
42
+
43
+ const activatedServices = selectActivatedServices(serviceIds, services);
44
+
45
+ const emailRequests = map(async (service) => {
46
+ const caoOrganization =
47
+ caoServiceRefs?.[service.serviceEndpoint]?.caoOrganization;
48
+ if (isEmpty(caoOrganization)) {
49
+ return;
50
+ }
51
+
52
+ const group = await repos.groups.findGroupByDid(
53
+ caoOrganization.didDoc.id
54
+ );
55
+ if (isEmpty(group?.clientAdminIds)) {
56
+ return;
57
+ }
58
+
59
+ const emails = map(
60
+ 'email',
61
+ await getUsersByIds({ userIds: group?.clientAdminIds })
62
+ );
63
+
64
+ try {
65
+ await sendEmail(
66
+ emailToCAOsForServicesActivation(
67
+ {
68
+ organization,
69
+ activatedService: service,
70
+ emails,
71
+ },
72
+ context
73
+ )
74
+ );
75
+ } catch (e) {
76
+ sendError(e, { message: e.message });
77
+ log.warn(
78
+ `Unable to send email for organization ${organization?.didDoc?.id} service ${service?.id}`
79
+ );
80
+ }
81
+ }, activatedServices);
82
+
83
+ await Promise.all(emailRequests);
84
+ };
85
+ };
86
+
87
+ module.exports = {
88
+ initSendActivationEmailsToCAOs,
89
+ };
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { map, isEmpty, compact, flow } = require('lodash/fp');
19
+ const { initAuth0Provisioner } = require('../../oauth');
20
+ const {
21
+ initOrganizationRegistrarEmails,
22
+ } = require('./init-organization-registrar-emails');
23
+
24
+ const mergeCaoServices = async (addedServices, caoServiceRefs) => {
25
+ return flow(
26
+ map((service) => {
27
+ const caoService = caoServiceRefs[service.serviceEndpoint]?.caoService;
28
+ return isEmpty(caoService) ? null : { ...service, caoService };
29
+ }),
30
+ compact
31
+ )(addedServices);
32
+ };
33
+
34
+ const initSendEmailInvitationAcceptedToInviter = (fastify) => {
35
+ const { sendEmail } = fastify;
36
+ const { getUsersByIds } = initAuth0Provisioner(fastify.config);
37
+ const { emailToGroupForInvitationAccepted } = initOrganizationRegistrarEmails(
38
+ fastify.config
39
+ );
40
+
41
+ return async (data, context) => {
42
+ const { repos } = context;
43
+ const { invitation, organization, addedServices, caoServiceRefs } = data;
44
+ if (isEmpty(invitation)) {
45
+ return;
46
+ }
47
+
48
+ const services = await mergeCaoServices(addedServices, caoServiceRefs);
49
+ if (isEmpty(services)) {
50
+ return;
51
+ }
52
+
53
+ const group = await repos.groups.findGroupByDid(invitation.inviterDid);
54
+ if (isEmpty(group?.clientAdminIds)) {
55
+ return;
56
+ }
57
+ const emails = map(
58
+ 'email',
59
+ await getUsersByIds({ userIds: group.clientAdminIds })
60
+ );
61
+
62
+ await sendEmail(
63
+ emailToGroupForInvitationAccepted({ organization, services, emails })
64
+ );
65
+ };
66
+ };
67
+
68
+ module.exports = {
69
+ initSendEmailInvitationAcceptedToInviter,
70
+ };
@@ -0,0 +1,212 @@
1
+ /*
2
+ * Copyright 2025 Velocity Team
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ const { isEmpty, omitBy, isNil, map } = require('lodash/fp');
19
+ const { optional } = require('@verii/common-functions');
20
+ const { initAuth0Provisioner } = require('../../oauth');
21
+ const { parseProfileToCsv, ServiceTypeLabels } = require('../domains');
22
+ const {
23
+ initOrganizationRegistrarEmails,
24
+ } = require('./init-organization-registrar-emails');
25
+
26
+ const initSendEmailNotifications = (initCtx) => {
27
+ const { config } = initCtx;
28
+ const {
29
+ emailToNewOrgForServicesActivated,
30
+ emailToSupportForOrgRegisteredAndServicesNeedActivation,
31
+ emailToSupportForServicesAddedAndNeedActivation,
32
+ emailToRegisteredOrgForServicesActivated,
33
+ } = initOrganizationRegistrarEmails(config);
34
+ const { getUsersByIds } = initAuth0Provisioner(config);
35
+
36
+ const shouldSendEmailForServicesActivated = (
37
+ activatedServiceIds,
38
+ userEmails
39
+ ) => {
40
+ return activatedServiceIds.length > 0 && !isEmpty(userEmails);
41
+ };
42
+
43
+ const shouldSendEmailForServicesNeedActivation = (
44
+ addedServices,
45
+ activatedServiceIds
46
+ ) => {
47
+ return (
48
+ addedServices.length > 0 &&
49
+ activatedServiceIds.length !== addedServices.length
50
+ );
51
+ };
52
+
53
+ const sendServiceNotification = async (
54
+ {
55
+ organization,
56
+ userEmails,
57
+ addedServices = [],
58
+ activatedServiceIds = [],
59
+ isCreateOrganization = false,
60
+ },
61
+ ctx
62
+ ) => {
63
+ const emailToServiceNeedActivation = isCreateOrganization
64
+ ? emailToSupportForOrgRegisteredAndServicesNeedActivation
65
+ : emailToSupportForServicesAddedAndNeedActivation;
66
+
67
+ const emailForServicesActivated = isCreateOrganization
68
+ ? emailToNewOrgForServicesActivated
69
+ : emailToRegisteredOrgForServicesActivated;
70
+
71
+ if (shouldSendEmailForServicesActivated(activatedServiceIds, userEmails)) {
72
+ await initCtx.sendEmail(
73
+ emailForServicesActivated({
74
+ organization,
75
+ activatedServiceIds,
76
+ emails: userEmails,
77
+ })
78
+ );
79
+ } else if (
80
+ shouldSendEmailForServicesNeedActivation(
81
+ addedServices,
82
+ activatedServiceIds
83
+ )
84
+ ) {
85
+ await initCtx.sendEmail(
86
+ emailToServiceNeedActivation(
87
+ {
88
+ organization,
89
+ addedServices,
90
+ },
91
+ ctx
92
+ )
93
+ );
94
+ }
95
+ };
96
+
97
+ const sendServiceNotificationToGroup = async (
98
+ {
99
+ organization,
100
+ addedServices,
101
+ activatedServiceIds,
102
+ isCreateOrganization = false,
103
+ },
104
+ ctx
105
+ ) => {
106
+ const { repos, user, log } = ctx;
107
+ const group = await repos.groups.findGroupByUserIdAndDid(
108
+ user.sub,
109
+ organization.didDoc.id
110
+ );
111
+ if (!group) {
112
+ const message = 'There was no group for organization';
113
+ log.info(
114
+ {
115
+ did: organization.didDoc.id,
116
+ user: user.sub,
117
+ },
118
+ message
119
+ );
120
+ return;
121
+ }
122
+
123
+ const { clientAdminIds } = group;
124
+ const userEmails = map(
125
+ 'email',
126
+ await getUsersByIds({ userIds: clientAdminIds })
127
+ );
128
+
129
+ await sendServiceNotification(
130
+ omitBy(isNil, {
131
+ organization,
132
+ userEmails,
133
+ addedServices,
134
+ activatedServiceIds,
135
+ isCreateOrganization,
136
+ }),
137
+ ctx
138
+ );
139
+ };
140
+
141
+ const sendOrganizationCreatedNotification = async (
142
+ { organization },
143
+ context
144
+ ) => {
145
+ const csvFile = await parseProfileToCsv(organization.profile);
146
+ await initCtx.sendEmail({
147
+ subject: await context.renderTemplate(
148
+ 'support-organization-created-subject',
149
+ {
150
+ organization,
151
+ }
152
+ ),
153
+ message: await context.renderTemplate(
154
+ 'support-organization-created-body',
155
+ {
156
+ organization,
157
+ }
158
+ ),
159
+ sender: config.noReplyEmail,
160
+ ccs: config.organizationCreationEmailCcList,
161
+ recipients: [config.registrarSupportEmail],
162
+ attachment: csvFile,
163
+ attachmentName: 'organization.csv',
164
+ contentType: 'text/csv',
165
+ });
166
+ };
167
+
168
+ const sendEmailToSignatoryForOrganizationApproval = async (
169
+ { organization, authCode, isReminder = false },
170
+ context
171
+ ) => {
172
+ const invitation = await optional(
173
+ () => context.repos.invitations.findById(organization.invitationId),
174
+ [organization.invitationId]
175
+ );
176
+ const inviterOrganization = invitation?.inviterDid
177
+ ? await context.repos.organizations.findOneByDid(invitation.inviterDid)
178
+ : null;
179
+ const html = await context.renderTemplate('signatory-approval-email-body', {
180
+ organization,
181
+ inviterOrganization,
182
+ authCode,
183
+ ServiceTypeLabels,
184
+ config,
185
+ });
186
+ await initCtx.sendEmail({
187
+ subject: `${isReminder ? 'Reminder: ' : ''}${
188
+ inviterOrganization?.profile?.name ??
189
+ `${organization.profile.adminGivenName} ${organization.profile.adminFamilyName}`
190
+ } is requesting your approval to register ${
191
+ organization.profile.name
192
+ } on the Velocity Network`,
193
+ message: html,
194
+ sender: config.registrarSupportEmail,
195
+ recipients: [organization.profile.signatoryEmail],
196
+ bccs: [config.signatoryVnfEmail],
197
+ replyTo: config.registrarSupportEmail,
198
+ html: true,
199
+ });
200
+ };
201
+
202
+ return {
203
+ sendServiceNotification,
204
+ sendServiceNotificationToGroup,
205
+ sendOrganizationCreatedNotification,
206
+ sendEmailToSignatoryForOrganizationApproval,
207
+ };
208
+ };
209
+
210
+ module.exports = {
211
+ initSendEmailNotifications,
212
+ };
@@ -0,0 +1,12 @@
1
+ const { uriToDidWeb } = require('@verii/did-web');
2
+
3
+ const buildCustodiedDidWeb = (profile, { config: { custodiedDidWebHost } }) => {
4
+ const profileUrl = new URL(profile.website);
5
+ const url = new URL(custodiedDidWebHost);
6
+ url.pathname = `/d/${profileUrl.hostname}`;
7
+ return uriToDidWeb(url.href);
8
+ };
9
+
10
+ module.exports = {
11
+ buildCustodiedDidWeb,
12
+ };
@@ -0,0 +1,40 @@
1
+ const { mapWithIndex } = require('@verii/common-functions');
2
+ const { mapKeyResponse } = require('../../organization-keys');
3
+
4
+ const buildProfileResponse = (organization, includeTimestamps = false) => {
5
+ const profile = {
6
+ ...organization.profile,
7
+ description: organization.profile.description || '',
8
+ id: organization.didDoc.id,
9
+ verifiableCredentialJwt: organization.verifiableCredentialJwt,
10
+ };
11
+ if (includeTimestamps) {
12
+ profile.updatedAt = organization.updatedAt;
13
+ profile.createdAt = organization.createdAt;
14
+ }
15
+
16
+ return profile;
17
+ };
18
+ const buildFullOrganizationResponse = ({
19
+ organization,
20
+ services,
21
+ profile,
22
+ keys,
23
+ keyPairs,
24
+ ...rest
25
+ }) => ({
26
+ id: organization.didDoc.id,
27
+ didDoc: organization.didDoc,
28
+ ids: organization.ids,
29
+ activatedServiceIds: organization.activatedServiceIds,
30
+ custodied: !organization.didNotCustodied,
31
+ profile: profile ?? buildProfileResponse(organization),
32
+ services: services ?? organization.services,
33
+ keys: keys != null ? buildOutgoingKeys(keys, keyPairs) : organization.keys,
34
+ ...rest,
35
+ });
36
+
37
+ const buildOutgoingKeys = (keys, keyPairs) =>
38
+ mapWithIndex((key, i) => mapKeyResponse(key, keyPairs[i]), keys);
39
+
40
+ module.exports = { buildFullOrganizationResponse, buildProfileResponse };