prow-authority 3.6.3

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 (168) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.dockerignore +11 -0
  3. package/.github/workflows/_deploy.yml +191 -0
  4. package/.github/workflows/deploy-dev.yml +30 -0
  5. package/.github/workflows/deploy-prod.yml +34 -0
  6. package/CLAUDE.md +114 -0
  7. package/Dockerfile +61 -0
  8. package/Dockerfile.dev +24 -0
  9. package/README.md +1 -0
  10. package/package.json +61 -0
  11. package/src/App.ts +40 -0
  12. package/src/helpers/api-error.ts +21 -0
  13. package/src/helpers/authority.ts +216 -0
  14. package/src/helpers/config.ts +4 -0
  15. package/src/helpers/holded.ts +105 -0
  16. package/src/helpers/mysql.ts +15 -0
  17. package/src/helpers/notifications.ts +55 -0
  18. package/src/helpers/random.ts +18 -0
  19. package/src/helpers/s3.ts +43 -0
  20. package/src/helpers/stripe.ts +8 -0
  21. package/src/index.ts +47 -0
  22. package/src/v1/common-types.ts +12 -0
  23. package/src/v1/controllers/admin/accounting-seat-controller.ts +148 -0
  24. package/src/v1/controllers/admin/billing-cycle-controller.ts +171 -0
  25. package/src/v1/controllers/admin/invoice-controller.ts +222 -0
  26. package/src/v1/controllers/admin/license-controller.ts +190 -0
  27. package/src/v1/controllers/admin/license-limit-controller.ts +160 -0
  28. package/src/v1/controllers/admin/notification-controller.ts +115 -0
  29. package/src/v1/controllers/admin/organization-controller.ts +210 -0
  30. package/src/v1/controllers/admin/organization-license-controller.ts +224 -0
  31. package/src/v1/controllers/admin/organization-license-limit-controller.ts +196 -0
  32. package/src/v1/controllers/admin/organization-usage-controller.ts +167 -0
  33. package/src/v1/controllers/admin/payment-method-controller.ts +173 -0
  34. package/src/v1/controllers/admin/policy-controller.ts +138 -0
  35. package/src/v1/controllers/admin/policy-version-controller.ts +143 -0
  36. package/src/v1/controllers/admin/schedule-controller.ts +181 -0
  37. package/src/v1/controllers/admin/service-controller.ts +206 -0
  38. package/src/v1/controllers/admin/service-notification-controller.ts +166 -0
  39. package/src/v1/controllers/admin/user-controller.ts +282 -0
  40. package/src/v1/controllers/admin/user-organization-controller.ts +172 -0
  41. package/src/v1/controllers/admin/user-policy-controller.ts +164 -0
  42. package/src/v1/controllers/auth/@deprecated oauth-controller.ts +191 -0
  43. package/src/v1/controllers/auth/identity-token-controller.ts +286 -0
  44. package/src/v1/controllers/auth/organization-token-controller.ts +277 -0
  45. package/src/v1/controllers/auth/temp-code-controller.ts +60 -0
  46. package/src/v1/controllers/billing/billing-controller.ts +805 -0
  47. package/src/v1/controllers/organizations/public-organization-controller.ts +1796 -0
  48. package/src/v1/controllers/policies/public-policy-controller.ts +68 -0
  49. package/src/v1/controllers/services/public-service-controller.ts +177 -0
  50. package/src/v1/controllers/services/service-controller.ts +474 -0
  51. package/src/v1/controllers/users/public-user-controller.ts +471 -0
  52. package/src/v1/daos/@deprecated auth-dao.ts +173 -0
  53. package/src/v1/daos/accounting-seat-dao.ts +111 -0
  54. package/src/v1/daos/billing-cycle-dao.ts +107 -0
  55. package/src/v1/daos/invoice-dao.ts +131 -0
  56. package/src/v1/daos/license-dao.ts +152 -0
  57. package/src/v1/daos/license-limit-dao.ts +120 -0
  58. package/src/v1/daos/organization-dao.ts +109 -0
  59. package/src/v1/daos/organization-license-dao.ts +117 -0
  60. package/src/v1/daos/organization-license-limit-dao.ts +157 -0
  61. package/src/v1/daos/organization-usage-dao.ts +115 -0
  62. package/src/v1/daos/payment-method-dao.ts +110 -0
  63. package/src/v1/daos/policy-dao.ts +105 -0
  64. package/src/v1/daos/policy-version-dao.ts +112 -0
  65. package/src/v1/daos/redis-dao.ts +38 -0
  66. package/src/v1/daos/schema.sql +462 -0
  67. package/src/v1/daos/service-dao.ts +118 -0
  68. package/src/v1/daos/service-notification-dao.ts +120 -0
  69. package/src/v1/daos/user-dao.ts +127 -0
  70. package/src/v1/daos/user-organization-dao.ts +123 -0
  71. package/src/v1/daos/user-policy-dao.ts +109 -0
  72. package/src/v1/middlewares/auth/identity-token-middleware.ts +51 -0
  73. package/src/v1/middlewares/auth/organization-token-middleware.ts +73 -0
  74. package/src/v1/middlewares/auth/service-token-middleware.ts +167 -0
  75. package/src/v1/middlewares/authority-middleware.ts +97 -0
  76. package/src/v1/middlewares/organizations/organization-middleware.ts +94 -0
  77. package/src/v1/middlewares/static/static-middleware.ts +41 -0
  78. package/src/v1/middlewares/users/user-middleware.ts +41 -0
  79. package/src/v1/routes/admin/accounting-seat-router.ts +89 -0
  80. package/src/v1/routes/admin/admin-router.ts +61 -0
  81. package/src/v1/routes/admin/billing-cycle-router.ts +89 -0
  82. package/src/v1/routes/admin/invoice-router.ts +89 -0
  83. package/src/v1/routes/admin/license-limit-router.ts +89 -0
  84. package/src/v1/routes/admin/license-router.ts +89 -0
  85. package/src/v1/routes/admin/notification-router.ts +61 -0
  86. package/src/v1/routes/admin/organization-license-limit-router.ts +89 -0
  87. package/src/v1/routes/admin/organization-license-router.ts +89 -0
  88. package/src/v1/routes/admin/organization-router.ts +89 -0
  89. package/src/v1/routes/admin/payment-method-router.ts +89 -0
  90. package/src/v1/routes/admin/policy-router.ts +89 -0
  91. package/src/v1/routes/admin/policy-version-router.ts +89 -0
  92. package/src/v1/routes/admin/schedule-router.ts +75 -0
  93. package/src/v1/routes/admin/service-notification-router.ts +98 -0
  94. package/src/v1/routes/admin/service-router.ts +89 -0
  95. package/src/v1/routes/admin/user-organization-router.ts +89 -0
  96. package/src/v1/routes/admin/user-policy-router.ts +89 -0
  97. package/src/v1/routes/admin/user-router.ts +89 -0
  98. package/src/v1/routes/auth/@deprecated auth-router.ts +199 -0
  99. package/src/v1/routes/auth/identity-token-router.ts +147 -0
  100. package/src/v1/routes/auth/organization-token-router.ts +70 -0
  101. package/src/v1/routes/billing/billing-router.ts +227 -0
  102. package/src/v1/routes/organizations/invoices-router.ts +48 -0
  103. package/src/v1/routes/organizations/payments-router.ts +104 -0
  104. package/src/v1/routes/organizations/public-organization-router.ts +319 -0
  105. package/src/v1/routes/organizations/users-router.ts +139 -0
  106. package/src/v1/routes/policies/public-policy-router.ts +50 -0
  107. package/src/v1/routes/services/public-service-router.ts +89 -0
  108. package/src/v1/routes/services/service-router.ts +197 -0
  109. package/src/v1/routes/users/public-user-router.ts +230 -0
  110. package/src/v1/routes/v1-router.ts +50 -0
  111. package/src/v1/schemas/admin/accounting-seat-schemas.ts +22 -0
  112. package/src/v1/schemas/admin/billing-cycle-schemas.ts +20 -0
  113. package/src/v1/schemas/admin/invoice-schemas.ts +41 -0
  114. package/src/v1/schemas/admin/license-limit-schemas.ts +25 -0
  115. package/src/v1/schemas/admin/license-schemas.ts +30 -0
  116. package/src/v1/schemas/admin/organization-license-limit-schemas.ts +29 -0
  117. package/src/v1/schemas/admin/organization-license-schemas.ts +43 -0
  118. package/src/v1/schemas/admin/organization-schemas.ts +67 -0
  119. package/src/v1/schemas/admin/organization-usage-schemas.ts +15 -0
  120. package/src/v1/schemas/admin/payment-method-schemas.ts +40 -0
  121. package/src/v1/schemas/admin/policy-schemas.ts +31 -0
  122. package/src/v1/schemas/admin/service-notification-schemas.ts +23 -0
  123. package/src/v1/schemas/admin/service-schemas.ts +56 -0
  124. package/src/v1/schemas/admin/user-organization-schemas.ts +24 -0
  125. package/src/v1/schemas/admin/user-policy-schemas.ts +17 -0
  126. package/src/v1/schemas/admin/user-schemas.ts +52 -0
  127. package/src/v1/schemas/auth/auth-schemas.ts +55 -0
  128. package/src/v1/schemas/billing/billing-schemas.ts +32 -0
  129. package/src/v1/schemas/organizations/public-organization-schemas.ts +77 -0
  130. package/src/v1/schemas/payments/payment-method-schemas.ts +0 -0
  131. package/src/v1/schemas/services/public-service-schemas.ts +5 -0
  132. package/src/v1/schemas/services/service-schemas.ts +27 -0
  133. package/src/v1/schemas/users/public-user-schemas.ts +73 -0
  134. package/src/v1/types/admin/accounting-seat-types.ts +16 -0
  135. package/src/v1/types/admin/billing-cycle-types.ts +14 -0
  136. package/src/v1/types/admin/invoice-types.ts +39 -0
  137. package/src/v1/types/admin/license-limit-types.ts +16 -0
  138. package/src/v1/types/admin/license-types.ts +29 -0
  139. package/src/v1/types/admin/organization-license-limit-types.ts +13 -0
  140. package/src/v1/types/admin/organization-license-types.ts +21 -0
  141. package/src/v1/types/admin/organization-types.ts +60 -0
  142. package/src/v1/types/admin/organization-usage-types.ts +17 -0
  143. package/src/v1/types/admin/payment-method-types.ts +30 -0
  144. package/src/v1/types/admin/policy-types.ts +9 -0
  145. package/src/v1/types/admin/policy-version-types.ts +12 -0
  146. package/src/v1/types/admin/service-notification-types.ts +20 -0
  147. package/src/v1/types/admin/service-types.ts +36 -0
  148. package/src/v1/types/admin/user-organization-types.ts +31 -0
  149. package/src/v1/types/admin/user-types.ts +44 -0
  150. package/src/v1/types/auth/@deprecated auth-types.ts +26 -0
  151. package/src/v1/types/auth/common-types.ts +7 -0
  152. package/src/v1/types/auth/confirmation-types.ts +5 -0
  153. package/src/v1/types/auth/identity-token-types.ts +8 -0
  154. package/src/v1/types/auth/organization-token-types.ts +23 -0
  155. package/src/v1/types/auth/otp-types.ts +12 -0
  156. package/src/v1/types/billing/billing-types.ts +37 -0
  157. package/src/v1/types/billing/ue-types.ts +29 -0
  158. package/src/v1/types/organizations/public-organization-types.ts +76 -0
  159. package/src/v1/types/policies/public-policy-types.ts +7 -0
  160. package/src/v1/types/services/public-service-types.ts +20 -0
  161. package/src/v1/types/services/service-types.ts +43 -0
  162. package/src/v1/types/users/public-user-types.ts +15 -0
  163. package/src/v1/types/users/user-policy-types.ts +11 -0
  164. package/static/error.html +55 -0
  165. package/static/grant.html +117 -0
  166. package/static/login.html +54 -0
  167. package/static/oauth-client-logo.webp +0 -0
  168. package/tsconfig.json +20 -0
@@ -0,0 +1,73 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import APIError, { StatusCodes } from '../../../helpers/api-error';
3
+ import organizationTokenController from '../../controllers/auth/organization-token-controller';
4
+ import RedisDao from '../../daos/redis-dao';
5
+ import { Environment } from '../../types/auth/organization-token-types';
6
+
7
+
8
+ class OrganizationTokenMiddleware {
9
+
10
+ private readonly CACHE_TIME = 60; // seconds
11
+ private readonly cache = new RedisDao<Environment>();
12
+
13
+ private readonly key = (token: string) =>
14
+ `authority:cache:organization:${token}`;
15
+
16
+ public readonly exists = async (req: any, res: Response, next: NextFunction) => {
17
+ try {
18
+ const access_token = (req.headers.authorization || ``).replace(`Bearer `, ``).trim();
19
+ if (!access_token) {
20
+ throw new APIError({
21
+ code: StatusCodes.UNAUTHORIZED,
22
+ detail: `No authorization provided.`,
23
+ });
24
+ }
25
+
26
+ req[`org_access_token`] = access_token;
27
+ next();
28
+ } catch (e) {
29
+ if (e instanceof APIError) {
30
+ res.status(e.code).json(e.data);
31
+ } else {
32
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
33
+ }
34
+ }
35
+ };
36
+
37
+ public readonly validate = async (req: Request, res: Response, next: NextFunction) => {
38
+ try {
39
+ if (!req[`org_access_token`]) {
40
+ throw new APIError({
41
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
42
+ detail: `Middleware dependency broken: required org_access_token missing.`,
43
+ });
44
+ }
45
+
46
+ const key = this.key(req[`org_access_token`]);
47
+ const cached = req.query[`cache`] === `false` ? null : await this.cache.get(key);
48
+ const env = cached || await organizationTokenController.check(req[`org_access_token`]);
49
+
50
+ req[`environment`] = env;
51
+ req[`user`] = env.user;
52
+ next();
53
+
54
+ // control cache as soon as possible - not critic
55
+ setImmediate(async () => {
56
+ try {
57
+ let updated: Environment;
58
+ if (cached) { updated = await organizationTokenController.check(req[`org_access_token`]); }
59
+ await this.cache.add(key, updated || env, this.CACHE_TIME);
60
+ } catch (e) { await this.cache.delete(key); }
61
+ });
62
+ } catch (e) {
63
+ if (e instanceof APIError) {
64
+ res.status(e.code).json(e.data);
65
+ } else {
66
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
67
+ }
68
+ }
69
+ };
70
+ }
71
+
72
+ const organizationTokenMiddleware = new OrganizationTokenMiddleware();
73
+ export default organizationTokenMiddleware;
@@ -0,0 +1,167 @@
1
+ import { Requester } from '@beseif-solutions/utility-functions/dist/utils/http-utils';
2
+ import { NextFunction, Request, Response } from 'express';
3
+ import _ from 'lodash';
4
+ import APIError, { StatusCodes } from '../../../helpers/api-error';
5
+ import organizationController from '../../controllers/admin/organization-controller';
6
+ import organizationLicenseController from '../../controllers/admin/organization-license-controller';
7
+ import serviceController from '../../controllers/admin/service-controller';
8
+ import RedisDao from '../../daos/redis-dao';
9
+ import { LicenseType } from '../../types/admin/license-types';
10
+ import { Organization, OrganizationStatus } from '../../types/admin/organization-types';
11
+ import { Service } from '../../types/admin/service-types';
12
+ import { ServiceEnvironment } from '../../types/services/service-types';
13
+
14
+
15
+ class ServiceTokenMiddleware {
16
+
17
+ private readonly CACHE_TIME = 60; // seconds
18
+ private readonly cache = new RedisDao<ServiceEnvironment>();
19
+
20
+ private readonly key = (service: string, org: string) =>
21
+ `authority:cache:service:${service}:organization:${org}`;
22
+
23
+ public readonly validate = async (req: Request, res: Response, next: NextFunction) => {
24
+ try {
25
+ const [serviceUUID, serviceToken] = [req.headers[`x-service-uuid`], req.headers[`x-service-token`], req.headers[`x-organization-uuid`]];
26
+ if (!serviceUUID || !serviceToken) {
27
+ throw new APIError({
28
+ code: StatusCodes.UNAUTHORIZED,
29
+ detail: `Invalid service identification: invalid headers.`,
30
+ });
31
+ }
32
+
33
+ // get service
34
+ const service = (await serviceController.list({ uuid: serviceUUID, token: serviceToken, enabled: true }))[0];
35
+ if (!service) {
36
+ throw new APIError({
37
+ code: StatusCodes.UNAUTHORIZED,
38
+ detail: `Invalid service identification: not enabled service found with provided information.`,
39
+ });
40
+ }
41
+
42
+ req[`service`] = service;
43
+ next();
44
+ } catch (e) {
45
+ if (e instanceof APIError) {
46
+ res.status(e.code).json(e.data);
47
+ } else {
48
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
49
+ }
50
+ }
51
+ };
52
+
53
+ private readonly environment = async (service: Service, organizationUUID: string) => {
54
+ try {
55
+ // get organization
56
+ const organization = (await organizationController.list({ uuid: organizationUUID, status: OrganizationStatus.Active }, { timestamp: true }))[0];
57
+ if (!organization) {
58
+ throw new APIError({
59
+ code: StatusCodes.UNAUTHORIZED,
60
+ detail: `Invalid organization identification: organization not found or is not active.`,
61
+ });
62
+ }
63
+
64
+ if (_.get(organization.internal, `services.${service.uuid}.blocked`, false)) {
65
+ throw new APIError({
66
+ code: StatusCodes.FORBIDDEN,
67
+ detail: `Invalid service access: organization access to service blocked.`,
68
+ });
69
+ }
70
+
71
+ // get licenses
72
+ const licenses = await this.licenses(service, organization);
73
+
74
+ const sEnv: ServiceEnvironment = {
75
+ organization: organization,
76
+ service: service,
77
+ licenses: licenses,
78
+ };
79
+ return sEnv;
80
+ } catch (e) { throw e; }
81
+ };
82
+
83
+ public readonly licenses = async (service: Service, organization: Organization) => {
84
+ try {
85
+ // get licenses
86
+ const licenses = await organizationLicenseController.list({
87
+ organization: organization.id,
88
+ service: service.id,
89
+ enabled: true,
90
+ });
91
+
92
+ const base = licenses.find((l) => l.type === LicenseType.Base);
93
+ if (!base) {
94
+ throw new APIError({
95
+ code: StatusCodes.UNAUTHORIZED,
96
+ detail: `Invalid service access: missing license.`,
97
+ });
98
+ }
99
+
100
+ if (base && typeof base.internal.notified === `boolean` && !base.internal.notified) {
101
+ // notify license change to service
102
+ if (service.internal.host && service.internal.organization?.modified) {
103
+ // update organization setup on service
104
+ Requester.patch(`${service.internal.organization?.modified}/${organization.uuid}`,
105
+ null,
106
+ {
107
+ baseURL: service.internal.host,
108
+ headers: {
109
+ "x-service-uuid": service.uuid,
110
+ "x-service-token": service.token,
111
+ },
112
+ }).catch(() => { /* TODO: what to do if the organization setup fails on service? */ });
113
+ }
114
+
115
+ await organizationLicenseController.update(base.id, { internal: { notified: null } });
116
+ }
117
+
118
+ return licenses;
119
+ } catch (e) { throw e; }
120
+ };
121
+
122
+ public readonly organization = async (req: Request, res: Response, next: NextFunction) => {
123
+ try {
124
+ if (!req[`service`]) {
125
+ throw new APIError({
126
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
127
+ detail: `Middleware dependency broken: required service missing.`,
128
+ });
129
+ }
130
+ const service: Service = req[`service`];
131
+
132
+ const organizationUUID = req.headers[`x-organization-uuid`] as string;
133
+ if (!organizationUUID) {
134
+ throw new APIError({
135
+ code: StatusCodes.UNAUTHORIZED,
136
+ detail: `Invalid service identification: invalid headers (organization).`,
137
+ });
138
+ }
139
+
140
+ const key = this.key(service.uuid, organizationUUID);
141
+ const cached = req.query[`cache`] === `false` ? null : await this.cache.get(key);
142
+ const env = cached || await this.environment(service, organizationUUID);
143
+
144
+ req[`service-environment`] = env;
145
+
146
+ next();
147
+
148
+ // control cache as soon as possible - not critic
149
+ setImmediate(async () => {
150
+ try {
151
+ let updated: ServiceEnvironment;
152
+ if (cached) { updated = await this.environment(service, organizationUUID); }
153
+ await this.cache.add(key, updated || env, this.CACHE_TIME);
154
+ } catch (e) { await this.cache.delete(key); }
155
+ });
156
+ } catch (e) {
157
+ if (e instanceof APIError) {
158
+ res.status(e.code).json(e.data);
159
+ } else {
160
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
161
+ }
162
+ }
163
+ };
164
+ }
165
+
166
+ const serviceTokenMiddleware = new ServiceTokenMiddleware();
167
+ export default serviceTokenMiddleware;
@@ -0,0 +1,97 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import APIError, { StatusCodes } from '../../helpers/api-error';
3
+ import authority, { LicenseLimitNames } from '../../helpers/authority';
4
+ import { Environment } from '../types/auth/organization-token-types';
5
+ import { QuotaUsage } from '@beseif-solutions/prow-authority-for-services';
6
+
7
+ class AuthorityMiddleware {
8
+
9
+ public readonly service = async (req: Request, res: Response, next: NextFunction) => {
10
+ try {
11
+ // validate headers
12
+ const [serviceUUID, serviceToken] = [req.headers[`x-service-uuid`], req.headers[`x-service-token`], req.headers[`x-organization-uuid`]];
13
+ if (!serviceUUID || !serviceToken) {
14
+ throw new APIError({
15
+ code: StatusCodes.UNAUTHORIZED,
16
+ detail: `Invalid service identification: invalid headers.`,
17
+ });
18
+ }
19
+
20
+ if (serviceUUID !== authority.configuration.uuid || serviceToken !== authority.configuration.token) {
21
+ throw new APIError({
22
+ code: StatusCodes.UNAUTHORIZED,
23
+ detail: `Invalid service identification: not matching headers.`,
24
+ });
25
+ }
26
+
27
+ next();
28
+ } catch (e) {
29
+ if (e instanceof APIError) {
30
+ res.status(e.code).json(e.data);
31
+ } else {
32
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
33
+ }
34
+ }
35
+ };
36
+
37
+ public readonly quota = (usage: QuotaUsage<LicenseLimitNames>) =>
38
+ async (req: Request, res: Response, next: NextFunction) => {
39
+ try {
40
+ if (!req[`environment`]) {
41
+ throw new APIError({
42
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
43
+ detail: `Middleware dependency broken: required environment missing.`,
44
+ });
45
+ }
46
+ const env: Environment = req[`environment`];
47
+
48
+ const possible = await authority.isPossible(env.organization.uuid, usage);
49
+ if (!possible) {
50
+ throw new APIError({
51
+ code: StatusCodes.FORBIDDEN,
52
+ detail: `Quota limit reached.`,
53
+ });
54
+ }
55
+ next();
56
+ } catch (e) {
57
+ if (e instanceof APIError) {
58
+ res.status(e.code).json(e.data);
59
+ } else {
60
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
61
+ }
62
+ }
63
+ };
64
+
65
+ public readonly licensed = async (req: Request, res: Response, next: NextFunction) => {
66
+ try {
67
+ if (!req[`environment`]) {
68
+ throw new APIError({
69
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
70
+ detail: `Middleware dependency broken: required environment missing.`,
71
+ });
72
+ }
73
+ const env: Environment = req[`environment`];
74
+
75
+
76
+ try {
77
+ await authority.organization(env.organization.uuid);
78
+ } catch (e) {
79
+ throw new APIError({
80
+ code: StatusCodes.FORBIDDEN,
81
+ detail: `Unlicensed access to service.`,
82
+ });
83
+ }
84
+ next();
85
+ } catch (e) {
86
+ if (e instanceof APIError) {
87
+ res.status(e.code).json(e.data);
88
+ } else {
89
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
90
+ }
91
+ }
92
+ };
93
+
94
+ }
95
+
96
+ const authorityMiddleware = new AuthorityMiddleware();
97
+ export default authorityMiddleware;
@@ -0,0 +1,94 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import APIError, { StatusCodes } from '../../../helpers/api-error';
3
+ import { OrganizationStatus } from '../../types/admin/organization-types';
4
+ import { Environment } from '../../types/auth/organization-token-types';
5
+ import { UserOrganizationRole } from '../../types/admin/user-organization-types';
6
+
7
+
8
+ class OrganizationMiddleware {
9
+ private readonly status = async (req: Request, res: Response, next: NextFunction, status: OrganizationStatus) => {
10
+ try {
11
+ if (!req[`environment`]) {
12
+ throw new APIError({
13
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
14
+ detail: `Middleware dependency broken: required environment missing.`,
15
+ });
16
+ }
17
+
18
+ if ((req[`environment`] as Environment).organization.status !== status) {
19
+ throw new APIError({
20
+ code: StatusCodes.FORBIDDEN,
21
+ detail: `Invalid organization status.`,
22
+ });
23
+ }
24
+
25
+ next();
26
+ } catch (e) {
27
+ if (e instanceof APIError) {
28
+ res.status(e.code).json(e.data);
29
+ } else {
30
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
31
+ }
32
+ }
33
+ };
34
+
35
+ // public readonly pending = async (req: Request, res: Response, next: NextFunction) =>
36
+ // this.status(req, res, next, OrganizationStatus.Pending);
37
+
38
+ // public readonly unpaid = async (req: Request, res: Response, next: NextFunction) =>
39
+ // this.status(req, res, next, OrganizationStatus.Unpaid);
40
+
41
+ public readonly active = async (req: Request, res: Response, next: NextFunction) =>
42
+ this.status(req, res, next, OrganizationStatus.Active);
43
+
44
+ private readonly role = async (req: Request, res: Response, next: NextFunction, role: UserOrganizationRole) => {
45
+ try {
46
+ if (!req[`environment`]) {
47
+ throw new APIError({
48
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
49
+ detail: `Middleware dependency broken: required environment missing.`,
50
+ });
51
+ }
52
+
53
+ const userAccess = (req[`environment`] as Environment).access;
54
+ if (userAccess.invite) {
55
+ throw new APIError({
56
+ code: StatusCodes.FORBIDDEN,
57
+ detail: `Forbidden access to organization: pending invite.`,
58
+ });
59
+ }
60
+
61
+ const order = [UserOrganizationRole.Staff, UserOrganizationRole.Admin, UserOrganizationRole.Owner];
62
+
63
+ const userRole = order.indexOf(userAccess.role);
64
+ const reqRole = order.indexOf(role);
65
+
66
+ if (userRole < reqRole) {
67
+ throw new APIError({
68
+ code: StatusCodes.FORBIDDEN,
69
+ detail: `Forbidden access to organization: invalid user role.`,
70
+ });
71
+ }
72
+
73
+ next();
74
+ } catch (e) {
75
+ if (e instanceof APIError) {
76
+ res.status(e.code).json(e.data);
77
+ } else {
78
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
79
+ }
80
+ }
81
+ };
82
+
83
+ public readonly owner = async (req: Request, res: Response, next: NextFunction) =>
84
+ this.role(req, res, next, UserOrganizationRole.Owner);
85
+
86
+ public readonly admin = async (req: Request, res: Response, next: NextFunction) =>
87
+ this.role(req, res, next, UserOrganizationRole.Admin);
88
+
89
+ public readonly staff = async (req: Request, res: Response, next: NextFunction) =>
90
+ this.role(req, res, next, UserOrganizationRole.Staff);
91
+ }
92
+
93
+ const organizationMiddleware = new OrganizationMiddleware();
94
+ export default organizationMiddleware;
@@ -0,0 +1,41 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import APIError, { StatusCodes } from '../../../helpers/api-error';
3
+ import nconf from '../../../helpers/config';
4
+
5
+ export const admin = async (req: Request, res: Response, next: NextFunction) => {
6
+ try {
7
+ const token = req.headers[`x-admin-token`];
8
+ if (token !== nconf.get(`SERVICES:AUTH:ADMIN`)) {
9
+ throw new APIError({
10
+ code: StatusCodes.UNAUTHORIZED,
11
+ detail: `No valid authorization provided for this environment.`,
12
+ });
13
+ }
14
+ next();
15
+ } catch (e) {
16
+ if (e instanceof APIError) {
17
+ res.status(e.code).json(e.data);
18
+ } else {
19
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
20
+ }
21
+ }
22
+ };
23
+
24
+ export const billing = async (req: Request, res: Response, next: NextFunction) => {
25
+ try {
26
+ const token = req.headers[`x-billing-token`];
27
+ if (token !== nconf.get(`SERVICES:AUTH:BILLING`)) {
28
+ throw new APIError({
29
+ code: StatusCodes.UNAUTHORIZED,
30
+ detail: `No valid authorization provided for this environment.`,
31
+ });
32
+ }
33
+ next();
34
+ } catch (e) {
35
+ if (e instanceof APIError) {
36
+ res.status(e.code).json(e.data);
37
+ } else {
38
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
39
+ }
40
+ }
41
+ };
@@ -0,0 +1,41 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import APIError, { StatusCodes } from '../../../helpers/api-error';
3
+ import { User, UserStatus } from '../../types/admin/user-types';
4
+
5
+
6
+ class UserMiddleware {
7
+ private readonly status = async (req: Request, res: Response, next: NextFunction, status: UserStatus) => {
8
+ try {
9
+ if (!req[`user`]) {
10
+ throw new APIError({
11
+ code: StatusCodes.INTERNAL_SERVER_ERROR,
12
+ detail: `Middleware dependency broken: required user missing.`,
13
+ });
14
+ }
15
+
16
+ if ((req[`user`] as User).status !== status) {
17
+ throw new APIError({
18
+ code: StatusCodes.FORBIDDEN,
19
+ detail: `Invalid user status.`,
20
+ });
21
+ }
22
+
23
+ next();
24
+ } catch (e) {
25
+ if (e instanceof APIError) {
26
+ res.status(e.code).json(e.data);
27
+ } else {
28
+ res.status(StatusCodes.UNAUTHORIZED).json({ error: e.message || e });
29
+ }
30
+ }
31
+ };
32
+
33
+ public readonly pending = async (req: Request, res: Response, next: NextFunction) =>
34
+ this.status(req, res, next, UserStatus.Pending);
35
+
36
+ public readonly active = async (req: Request, res: Response, next: NextFunction) =>
37
+ this.status(req, res, next, UserStatus.Active);
38
+ }
39
+
40
+ const userMiddleware = new UserMiddleware();
41
+ export default userMiddleware;
@@ -0,0 +1,89 @@
1
+ import { Request, Router, Response } from 'express';
2
+ import accountingSeatController from '../../controllers/admin/accounting-seat-controller';
3
+ import httpcodes from 'http-status-codes';
4
+ import APIError from '../../../helpers/api-error';
5
+
6
+ class AccountingSeatRouter {
7
+ router: Router;
8
+
9
+ constructor() {
10
+ this.router = Router();
11
+ this.init();
12
+ }
13
+
14
+ private readonly get = async (req: Request, res: Response) => {
15
+ try {
16
+ const response = await accountingSeatController.get(parseInt(req.params[`id`], 10));
17
+ res.json(response);
18
+ } catch (e) {
19
+ if (e instanceof APIError) {
20
+ res.status(e.code).json(e.data);
21
+ } else {
22
+ res.status(httpcodes.INTERNAL_SERVER_ERROR).json({ error: e.message || e });
23
+ }
24
+ }
25
+ };
26
+
27
+ private readonly list = async (req: Request, res: Response) => {
28
+ try {
29
+ const response = await accountingSeatController.list(req.body);
30
+ res.json(response);
31
+ } catch (e) {
32
+ if (e instanceof APIError) {
33
+ res.status(e.code).json(e.data);
34
+ } else {
35
+ res.status(httpcodes.INTERNAL_SERVER_ERROR).json({ error: e.message || e });
36
+ }
37
+ }
38
+ };
39
+
40
+ private readonly add = async (req: Request, res: Response) => {
41
+ try {
42
+ const response = await accountingSeatController.add(req.body);
43
+ res.json(response);
44
+ } catch (e) {
45
+ if (e instanceof APIError) {
46
+ res.status(e.code).json(e.data);
47
+ } else {
48
+ res.status(httpcodes.INTERNAL_SERVER_ERROR).json({ error: e.message || e });
49
+ }
50
+ }
51
+ };
52
+
53
+ private readonly update = async (req: Request, res: Response) => {
54
+ try {
55
+ const response = await accountingSeatController.update(parseInt(req.params[`id`], 10), req.body);
56
+ res.json(response);
57
+ } catch (e) {
58
+ if (e instanceof APIError) {
59
+ res.status(e.code).json(e.data);
60
+ } else {
61
+ res.status(httpcodes.INTERNAL_SERVER_ERROR).json({ error: e.message || e });
62
+ }
63
+ }
64
+ };
65
+
66
+ private readonly delete = async (req: Request, res: Response) => {
67
+ try {
68
+ const response = await accountingSeatController.delete(parseInt(req.params[`id`], 10));
69
+ res.json(response);
70
+ } catch (e) {
71
+ if (e instanceof APIError) {
72
+ res.status(e.code).json(e.data);
73
+ } else {
74
+ res.status(httpcodes.INTERNAL_SERVER_ERROR).json({ error: e.message || e });
75
+ }
76
+ }
77
+ };
78
+
79
+ private readonly init = () => {
80
+ this.router.get(`/:id`, this.get);
81
+ this.router.post(`/list`, this.list);
82
+ this.router.post(`/`, this.add);
83
+ this.router.put(`/:id`, this.update);
84
+ this.router.delete(`/:id`, this.delete);
85
+ };
86
+ }
87
+
88
+ const accountingSeatRouter = (new AccountingSeatRouter()).router;
89
+ export default accountingSeatRouter;
@@ -0,0 +1,61 @@
1
+ import { Router } from 'express';
2
+ import { admin } from '../../middlewares/static/static-middleware';
3
+ import accountingSeatRouter from './accounting-seat-router';
4
+ import billingCycleRouter from './billing-cycle-router';
5
+ import invoiceRouter from './invoice-router';
6
+ import licenseLimitRouter from './license-limit-router';
7
+ import licenseRouter from './license-router';
8
+ import notificationRouter from './notification-router';
9
+ import organizationLicenseLimitRouter from './organization-license-limit-router';
10
+ import organizationLicenseRouter from './organization-license-router';
11
+ import organizationRouter from './organization-router';
12
+ import paymentMethodRouter from './payment-method-router';
13
+ import policyRouter from './policy-router';
14
+ import policyVersionRouter from './policy-version-router';
15
+ import scheduleRouter from './schedule-router';
16
+ import serviceNotificationRouter from './service-notification-router';
17
+ import serviceRouter from './service-router';
18
+ import userOrganizationRouter from './user-organization-router';
19
+ import userPolicyRouter from './user-policy-router';
20
+ import userRouter from './user-router';
21
+
22
+ class AdminRouter {
23
+ router: Router;
24
+
25
+ constructor() {
26
+ this.router = Router();
27
+ this.init();
28
+ }
29
+
30
+ private readonly init = () => {
31
+ this.router.use(admin);
32
+
33
+ this.router.use(`/policies`, policyRouter);
34
+ this.router.use(`/policy-versions`, policyVersionRouter);
35
+
36
+ this.router.use(`/services`, serviceRouter);
37
+ this.router.use(`/licenses`, licenseRouter);
38
+ this.router.use(`/license-limits`, licenseLimitRouter);
39
+ this.router.use(`/service-notifications`, serviceNotificationRouter);
40
+
41
+ this.router.use(`/organizations`, organizationRouter);
42
+ this.router.use(`/organization-licenses`, organizationLicenseRouter);
43
+ this.router.use(`/organization-license-limits`, organizationLicenseLimitRouter);
44
+ this.router.use(`/users`, userRouter);
45
+ this.router.use(`/access`, userOrganizationRouter);
46
+ this.router.use(`/user-policies`, userPolicyRouter);
47
+ this.router.use(`/notifications`, notificationRouter);
48
+
49
+ this.router.use(`/billing-cycles`, billingCycleRouter);
50
+ this.router.use(`/payment-methods`, paymentMethodRouter);
51
+ this.router.use(`/invoices`, invoiceRouter);
52
+ this.router.use(`/accounting-seats`, accountingSeatRouter);
53
+
54
+ this.router.use(`/schedules`, scheduleRouter);
55
+ };
56
+ }
57
+
58
+ const adminRouter = (new AdminRouter()).router;
59
+ export default adminRouter;
60
+
61
+