@appweaver/core 1.0.0
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.
- package/LICENSE +1 -0
- package/README.md +7 -0
- package/app/application.d.ts +43 -0
- package/app/application.js +112 -0
- package/app/create-app.d.ts +32 -0
- package/app/create-app.js +38 -0
- package/app/index.d.ts +2 -0
- package/app/index.js +18 -0
- package/app/lifecycle-manager.d.ts +20 -0
- package/app/lifecycle-manager.js +42 -0
- package/app/load-modules.d.ts +10 -0
- package/app/load-modules.js +50 -0
- package/app/load-providers.d.ts +8 -0
- package/app/load-providers.js +33 -0
- package/cache/cache-service.d.ts +72 -0
- package/cache/cache-service.js +202 -0
- package/cache/cache.d.ts +12 -0
- package/cache/cache.js +184 -0
- package/cache/caching.d.ts +8 -0
- package/cache/caching.js +72 -0
- package/cache/eviction/eviction-index.d.ts +35 -0
- package/cache/eviction/eviction-index.js +2 -0
- package/cache/eviction/fifo-eviction-index.d.ts +7 -0
- package/cache/eviction/fifo-eviction-index.js +28 -0
- package/cache/eviction/index.d.ts +4 -0
- package/cache/eviction/index.js +20 -0
- package/cache/eviction/lfu-eviction-index.d.ts +8 -0
- package/cache/eviction/lfu-eviction-index.js +82 -0
- package/cache/eviction/lru-eviction-index.d.ts +8 -0
- package/cache/eviction/lru-eviction-index.js +81 -0
- package/cache/index.d.ts +2 -0
- package/cache/index.js +18 -0
- package/cache/memory-cache.d.ts +4 -0
- package/cache/memory-cache.js +12 -0
- package/cache/redis-cache.d.ts +4 -0
- package/cache/redis-cache.js +12 -0
- package/context/context.d.ts +2 -0
- package/context/context.js +13 -0
- package/context/dependency-injection.d.ts +98 -0
- package/context/dependency-injection.js +276 -0
- package/context/index.d.ts +2 -0
- package/context/index.js +18 -0
- package/database/create-client.d.ts +11 -0
- package/database/create-client.js +142 -0
- package/database/index.d.ts +1 -0
- package/database/index.js +17 -0
- package/database/prisma-database.d.ts +15 -0
- package/database/prisma-database.js +53 -0
- package/errors/error-handler.d.ts +3 -0
- package/errors/error-handler.js +24 -0
- package/errors/error-schema.d.ts +32 -0
- package/errors/error-schema.js +31 -0
- package/errors/http-error.d.ts +21 -0
- package/errors/http-error.js +33 -0
- package/errors/index.d.ts +3 -0
- package/errors/index.js +19 -0
- package/events/node-events.d.ts +7 -0
- package/events/node-events.js +39 -0
- package/export/export-service.d.ts +19 -0
- package/export/export-service.js +154 -0
- package/export/index.d.ts +1 -0
- package/export/index.js +17 -0
- package/factory/create-model.d.ts +2 -0
- package/factory/create-model.js +366 -0
- package/factory/create-policy.d.ts +2 -0
- package/factory/create-policy.js +16 -0
- package/factory/create-routes.d.ts +2 -0
- package/factory/create-routes.js +21 -0
- package/factory/create-service.d.ts +3 -0
- package/factory/create-service.js +97 -0
- package/factory/index.d.ts +4 -0
- package/factory/index.js +20 -0
- package/health/health-routes.d.ts +2 -0
- package/health/health-routes.js +36 -0
- package/health/health-schema.d.ts +45 -0
- package/health/health-schema.js +52 -0
- package/health/health-service.d.ts +38 -0
- package/health/health-service.js +82 -0
- package/health/index.d.ts +2 -0
- package/health/index.js +18 -0
- package/index.d.ts +15 -0
- package/index.js +31 -0
- package/mailer/email-service.d.ts +36 -0
- package/mailer/email-service.js +89 -0
- package/mailer/index.d.ts +1 -0
- package/mailer/index.js +17 -0
- package/mailer/json-mailer.d.ts +7 -0
- package/mailer/json-mailer.js +32 -0
- package/mailer/smtp-mailer.d.ts +7 -0
- package/mailer/smtp-mailer.js +43 -0
- package/memory/in-memory.d.ts +24 -0
- package/memory/in-memory.js +164 -0
- package/memory/redis.d.ts +26 -0
- package/memory/redis.js +158 -0
- package/package.json +68 -0
- package/prisma/client/browser.d.ts +34 -0
- package/prisma/client/browser.js +56 -0
- package/prisma/client/client.d.ts +53 -0
- package/prisma/client/client.js +70 -0
- package/prisma/client/commonInputTypes.d.ts +395 -0
- package/prisma/client/commonInputTypes.js +11 -0
- package/prisma/client/enums.d.ts +1 -0
- package/prisma/client/enums.js +11 -0
- package/prisma/client/internal/class.d.ts +187 -0
- package/prisma/client/internal/class.js +85 -0
- package/prisma/client/internal/prismaNamespace.d.ts +987 -0
- package/prisma/client/internal/prismaNamespace.js +193 -0
- package/prisma/client/internal/prismaNamespaceBrowser.d.ts +125 -0
- package/prisma/client/internal/prismaNamespaceBrowser.js +164 -0
- package/prisma/client/models/ApiKey.d.ts +1167 -0
- package/prisma/client/models/ApiKey.js +2 -0
- package/prisma/client/models/File.d.ts +1248 -0
- package/prisma/client/models/File.js +2 -0
- package/prisma/client/models/OneTimeToken.d.ts +1083 -0
- package/prisma/client/models/OneTimeToken.js +2 -0
- package/prisma/client/models/Permission.d.ts +1209 -0
- package/prisma/client/models/Permission.js +2 -0
- package/prisma/client/models/Role.d.ts +1209 -0
- package/prisma/client/models/Role.js +2 -0
- package/prisma/client/models/Seeder.d.ts +1023 -0
- package/prisma/client/models/Seeder.js +2 -0
- package/prisma/client/models.d.ts +7 -0
- package/prisma/client/models.js +2 -0
- package/queue/bull-queue.d.ts +37 -0
- package/queue/bull-queue.js +207 -0
- package/queue/memory-queue.d.ts +54 -0
- package/queue/memory-queue.js +283 -0
- package/resource/index.d.ts +4 -0
- package/resource/index.js +20 -0
- package/resource/resource-loader.d.ts +26 -0
- package/resource/resource-loader.js +161 -0
- package/resource/resource-routes.d.ts +3 -0
- package/resource/resource-routes.js +174 -0
- package/resource/resource-schema.d.ts +33 -0
- package/resource/resource-schema.js +186 -0
- package/resource/resource-service.d.ts +89 -0
- package/resource/resource-service.js +772 -0
- package/resources.d.ts +9 -0
- package/resources.js +24 -0
- package/scheduler/cron-scheduler.d.ts +12 -0
- package/scheduler/cron-scheduler.js +73 -0
- package/security/account/account-routes.d.ts +2 -0
- package/security/account/account-routes.js +104 -0
- package/security/account/account-schema.d.ts +290 -0
- package/security/account/account-schema.js +166 -0
- package/security/account/account-service.d.ts +88 -0
- package/security/account/account-service.js +218 -0
- package/security/account/index.d.ts +3 -0
- package/security/account/index.js +19 -0
- package/security/api-key/api-key-auth.d.ts +4 -0
- package/security/api-key/api-key-auth.js +66 -0
- package/security/api-key/index.d.ts +1 -0
- package/security/api-key/index.js +17 -0
- package/security/auth-routes.d.ts +2 -0
- package/security/auth-routes.js +80 -0
- package/security/auth-schema.d.ts +215 -0
- package/security/auth-schema.js +129 -0
- package/security/auth-service.d.ts +117 -0
- package/security/auth-service.js +272 -0
- package/security/auth.d.ts +3 -0
- package/security/auth.js +127 -0
- package/security/basic/basic-auth.d.ts +4 -0
- package/security/basic/basic-auth.js +32 -0
- package/security/basic/index.d.ts +1 -0
- package/security/basic/index.js +17 -0
- package/security/create-auth-resources.d.ts +6 -0
- package/security/create-auth-resources.js +129 -0
- package/security/helper.d.ts +127 -0
- package/security/helper.js +329 -0
- package/security/index.d.ts +4 -0
- package/security/index.js +20 -0
- package/security/jwt/index.d.ts +2 -0
- package/security/jwt/index.js +18 -0
- package/security/jwt/jwt-auth.d.ts +4 -0
- package/security/jwt/jwt-auth.js +57 -0
- package/security/jwt/jwt-keys.d.ts +7 -0
- package/security/jwt/jwt-keys.js +43 -0
- package/security/oauth2/create-oauth2-plugin.d.ts +17 -0
- package/security/oauth2/create-oauth2-plugin.js +85 -0
- package/security/oauth2/index.d.ts +3 -0
- package/security/oauth2/index.js +19 -0
- package/security/oauth2/oauth2-custom.d.ts +7 -0
- package/security/oauth2/oauth2-custom.js +40 -0
- package/security/oauth2/oauth2-facebook.d.ts +1 -0
- package/security/oauth2/oauth2-facebook.js +30 -0
- package/security/oauth2/oauth2-google.d.ts +1 -0
- package/security/oauth2/oauth2-google.js +28 -0
- package/security/oauth2/oauth2-schema.d.ts +10 -0
- package/security/oauth2/oauth2-schema.js +53 -0
- package/security/recaptcha/index.d.ts +2 -0
- package/security/recaptcha/index.js +18 -0
- package/security/recaptcha/recaptcha-verify.d.ts +1 -0
- package/security/recaptcha/recaptcha-verify.js +33 -0
- package/security/recaptcha/recaptcha.d.ts +2 -0
- package/security/recaptcha/recaptcha.js +22 -0
- package/security/resources/api-key/model.d.ts +2 -0
- package/security/resources/api-key/model.js +63 -0
- package/security/resources/api-key/policy.d.ts +2 -0
- package/security/resources/api-key/policy.js +26 -0
- package/security/resources/api-key/routes.d.ts +2 -0
- package/security/resources/api-key/routes.js +15 -0
- package/security/resources/api-key/service.d.ts +3 -0
- package/security/resources/api-key/service.js +33 -0
- package/security/resources/one-time-token/model.d.ts +2 -0
- package/security/resources/one-time-token/model.js +32 -0
- package/security/resources/permission/model.d.ts +2 -0
- package/security/resources/permission/model.js +16 -0
- package/security/resources/role/model.d.ts +2 -0
- package/security/resources/role/model.js +22 -0
- package/security/store/database-security-store.d.ts +5 -0
- package/security/store/database-security-store.js +51 -0
- package/security/store/redis-security-store.d.ts +5 -0
- package/security/store/redis-security-store.js +32 -0
- package/seeder/create-seeder.d.ts +21 -0
- package/seeder/create-seeder.js +17 -0
- package/seeder/index.d.ts +2 -0
- package/seeder/index.js +18 -0
- package/seeder/resources/seeder/model.d.ts +2 -0
- package/seeder/resources/seeder/model.js +38 -0
- package/seeder/seeder.d.ts +20 -0
- package/seeder/seeder.js +175 -0
- package/server/create-server.d.ts +20 -0
- package/server/create-server.js +160 -0
- package/server/index.d.ts +4 -0
- package/server/index.js +20 -0
- package/server/info-route.d.ts +2 -0
- package/server/info-route.js +18 -0
- package/server/info-schema.d.ts +37 -0
- package/server/info-schema.js +19 -0
- package/server/register-model.d.ts +2 -0
- package/server/register-model.js +12 -0
- package/server/register-plugin.d.ts +2 -0
- package/server/register-plugin.js +13 -0
- package/server/register-route.d.ts +3 -0
- package/server/register-route.js +74 -0
- package/server/schemas.d.ts +3 -0
- package/server/schemas.js +30 -0
- package/server/swagger.d.ts +3 -0
- package/server/swagger.js +122 -0
- package/storage/file-route.d.ts +2 -0
- package/storage/file-route.js +39 -0
- package/storage/file-schema.d.ts +9 -0
- package/storage/file-schema.js +42 -0
- package/storage/file-service.d.ts +81 -0
- package/storage/file-service.js +384 -0
- package/storage/filesystem-storage.d.ts +10 -0
- package/storage/filesystem-storage.js +128 -0
- package/storage/index.d.ts +2 -0
- package/storage/index.js +18 -0
- package/storage/resources/file/model.d.ts +2 -0
- package/storage/resources/file/model.js +75 -0
- package/types/application-context.d.ts +20 -0
- package/types/application-context.js +2 -0
- package/types/auth.d.ts +31 -0
- package/types/auth.js +2 -0
- package/types/fastify-extensions.d.ts +24 -0
- package/types/fastify-extensions.js +4 -0
- package/types/generated.d.ts +193 -0
- package/types/generated.js +3 -0
- package/types/index.d.ts +4 -0
- package/types/index.js +20 -0
- package/types/server.d.ts +4 -0
- package/types/server.js +2 -0
- package/utils/export-util.d.ts +8 -0
- package/utils/export-util.js +25 -0
- package/utils/file-util.d.ts +64 -0
- package/utils/file-util.js +141 -0
- package/utils/index.d.ts +3 -0
- package/utils/index.js +19 -0
- package/utils/schema-util.d.ts +20 -0
- package/utils/schema-util.js +37 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createOAuth2Plugin = createOAuth2Plugin;
|
|
7
|
+
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
8
|
+
const oauth2_1 = __importDefault(require("@fastify/oauth2"));
|
|
9
|
+
const common_1 = require("@appweaver/common");
|
|
10
|
+
const context_1 = require("../../context");
|
|
11
|
+
const errors_1 = require("../../errors");
|
|
12
|
+
const auth_service_1 = require("../auth-service");
|
|
13
|
+
const helper_1 = require("../helper");
|
|
14
|
+
const oauth2_schema_1 = require("./oauth2-schema");
|
|
15
|
+
function createOAuth2Plugin(authSource, oAuth2Config) {
|
|
16
|
+
const name = authSource.replace('oauth2', '');
|
|
17
|
+
const upperName = name.toUpperCase();
|
|
18
|
+
const lowerName = name.toLowerCase();
|
|
19
|
+
return (0, fastify_plugin_1.default)(async (server) => {
|
|
20
|
+
if (!oAuth2Config.enabled) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (!oAuth2Config.clientId || !oAuth2Config.clientSecret) {
|
|
24
|
+
throw Error(`${name} OAuth2 configuration is missing`);
|
|
25
|
+
}
|
|
26
|
+
if (server[authSource] !== undefined) {
|
|
27
|
+
throw Error(`${name} OAuth2 provider is already registered`);
|
|
28
|
+
}
|
|
29
|
+
const authConfig = oauth2_1.default[`${upperName}_CONFIGURATION`];
|
|
30
|
+
if (!authConfig && !oAuth2Config.issuer) {
|
|
31
|
+
throw Error(`${name} OAuth2 provider is not supported`);
|
|
32
|
+
}
|
|
33
|
+
const authService = (0, context_1.inject)(auth_service_1.AuthService);
|
|
34
|
+
const securityStore = (0, context_1.inject)(common_1.SecurityStore);
|
|
35
|
+
const prefix = common_1.config.SECURITY_ROUTE_PREFIX.replace(/\/$/, '');
|
|
36
|
+
server.register(oauth2_1.default, {
|
|
37
|
+
name: authSource,
|
|
38
|
+
credentials: {
|
|
39
|
+
client: {
|
|
40
|
+
id: oAuth2Config.clientId,
|
|
41
|
+
secret: oAuth2Config.clientSecret
|
|
42
|
+
},
|
|
43
|
+
auth: authConfig
|
|
44
|
+
},
|
|
45
|
+
...(oAuth2Config.issuer
|
|
46
|
+
? { discovery: { issuer: oAuth2Config.issuer } }
|
|
47
|
+
: {}),
|
|
48
|
+
scope: oAuth2Config.scope,
|
|
49
|
+
schema: (0, oauth2_schema_1.createOAuth2RedirectSchema)(name),
|
|
50
|
+
startRedirectPath: `${prefix}/login/${lowerName}`,
|
|
51
|
+
callbackUri: `${common_1.config.APP_HOSTNAME}${prefix}/login/${lowerName}/callback`,
|
|
52
|
+
generateStateFunction: async (request) => {
|
|
53
|
+
const redirectToUrl = request.query.redirectToUrl;
|
|
54
|
+
const result = (0, helper_1.validateRedirectUrl)(redirectToUrl);
|
|
55
|
+
if (!result.valid) {
|
|
56
|
+
throw new errors_1.HttpError(result.message, 400);
|
|
57
|
+
}
|
|
58
|
+
return securityStore.generateOneTimeToken(common_1.AuthOTTPurpose.OAuth2State, { redirectToUrl }, common_1.config.SECURITY_OAUTH2_STATE_TTL);
|
|
59
|
+
},
|
|
60
|
+
checkStateFunction: async (request) => {
|
|
61
|
+
const state = request.query.state;
|
|
62
|
+
request.oauth2State =
|
|
63
|
+
await securityStore.useOneTimeToken(state, common_1.AuthOTTPurpose.OAuth2State);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
server.get(`${prefix}/login/${lowerName}/callback`, {
|
|
68
|
+
schema: (0, oauth2_schema_1.createOAuth2CallbackSchema)(name)
|
|
69
|
+
}, async function (request, reply) {
|
|
70
|
+
const { token } = await server[authSource].getAccessTokenFromAuthorizationCodeFlow(request);
|
|
71
|
+
const userInfo = await oAuth2Config.extractUserInfo(token.access_token);
|
|
72
|
+
let authUser = await authService.findByUsername(userInfo.email);
|
|
73
|
+
if (!authUser) {
|
|
74
|
+
authUser = await authService.registerAuthUser(authSource, userInfo.email, undefined, (0, common_1.pickProperties)(userInfo, ['firstName', 'lastName']));
|
|
75
|
+
}
|
|
76
|
+
else if (!authUser.verifiedEmail) {
|
|
77
|
+
throw new errors_1.HttpError('Auth user email address is not verified', 403);
|
|
78
|
+
}
|
|
79
|
+
const stateData = request.oauth2State;
|
|
80
|
+
const ott = await securityStore.generateOneTimeToken(common_1.AuthOTTPurpose.Authentication, { authUserId: authUser.id, authSource }, common_1.config.SECURITY_AUTH_OTT_TTL);
|
|
81
|
+
const separator = stateData.redirectToUrl.includes('?') ? '&' : '?';
|
|
82
|
+
return reply.redirect(`${stateData.redirectToUrl}${separator}token=${ott}`);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./oauth2-custom"), exports);
|
|
18
|
+
__exportStar(require("./oauth2-facebook"), exports);
|
|
19
|
+
__exportStar(require("./oauth2-google"), exports);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oauth2Custom = void 0;
|
|
4
|
+
const common_1 = require("@appweaver/common");
|
|
5
|
+
const context_1 = require("../../context");
|
|
6
|
+
const errors_1 = require("../../errors");
|
|
7
|
+
const create_oauth2_plugin_1 = require("./create-oauth2-plugin");
|
|
8
|
+
exports.oauth2Custom = (0, create_oauth2_plugin_1.createOAuth2Plugin)(common_1.AuthSource.OAuth2Custom, {
|
|
9
|
+
enabled: common_1.config.SECURITY_OAUTH2_CUSTOM_ENABLED,
|
|
10
|
+
clientId: common_1.config.SECURITY_OAUTH2_CUSTOM_CLIENT_ID,
|
|
11
|
+
clientSecret: common_1.config.SECURITY_OAUTH2_CUSTOM_CLIENT_SECRET,
|
|
12
|
+
issuer: common_1.config.SECURITY_OAUTH2_CUSTOM_ISSUER,
|
|
13
|
+
scope: ['openid', 'profile', 'email'],
|
|
14
|
+
extractUserInfo: (accessToken) => fetchCustomUser(accessToken)
|
|
15
|
+
});
|
|
16
|
+
async function fetchCustomUser(accessToken) {
|
|
17
|
+
const server = context_1.context.server;
|
|
18
|
+
if (!server) {
|
|
19
|
+
throw new errors_1.HttpError('Server is not available', 500);
|
|
20
|
+
}
|
|
21
|
+
const customOauth2 = server[common_1.AuthSource.OAuth2Custom];
|
|
22
|
+
let data;
|
|
23
|
+
if (typeof customOauth2?.userinfo === 'function') {
|
|
24
|
+
data = (await customOauth2.userinfo(accessToken));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Fallback to direct API call if the plugin is not initialized
|
|
28
|
+
const resp = await fetch(`${common_1.config.SECURITY_OAUTH2_CUSTOM_ISSUER}/protocol/openid-connect/userinfo`, { method: 'GET', headers: { authorization: `Bearer ${accessToken}` } });
|
|
29
|
+
if (!resp.ok) {
|
|
30
|
+
throw new errors_1.HttpError(`Custom OAuth2 API error: ${resp.status} ${resp.statusText}`, 500);
|
|
31
|
+
}
|
|
32
|
+
data = await resp.json();
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
id: data.sub,
|
|
36
|
+
email: data.email,
|
|
37
|
+
firstName: data.given_name,
|
|
38
|
+
lastName: data.family_name
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const oauth2Facebook: (server: import("../..").Server) => Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oauth2Facebook = void 0;
|
|
4
|
+
const common_1 = require("@appweaver/common");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
const create_oauth2_plugin_1 = require("./create-oauth2-plugin");
|
|
7
|
+
exports.oauth2Facebook = (0, create_oauth2_plugin_1.createOAuth2Plugin)(common_1.AuthSource.OAuth2Facebook, {
|
|
8
|
+
enabled: common_1.config.SECURITY_OAUTH2_FACEBOOK_ENABLED,
|
|
9
|
+
clientId: common_1.config.SECURITY_OAUTH2_FACEBOOK_CLIENT_ID,
|
|
10
|
+
clientSecret: common_1.config.SECURITY_OAUTH2_FACEBOOK_CLIENT_SECRET,
|
|
11
|
+
scope: ['public_profile', 'email'],
|
|
12
|
+
extractUserInfo: (accessToken) => fetchFacebookUser(accessToken)
|
|
13
|
+
});
|
|
14
|
+
async function fetchFacebookUser(accessToken) {
|
|
15
|
+
const params = new URLSearchParams();
|
|
16
|
+
params.append('fields', 'id,name,email');
|
|
17
|
+
params.append('access_token', accessToken);
|
|
18
|
+
const resp = await fetch(`${common_1.config.SECURITY_OAUTH2_FACEBOOK_USER_INFO_URL}?${params}`, { method: 'GET' });
|
|
19
|
+
if (!resp.ok) {
|
|
20
|
+
throw new errors_1.HttpError(`Facebook Graph API error: ${resp.status} ${resp.statusText}`, 500);
|
|
21
|
+
}
|
|
22
|
+
const data = await resp.json();
|
|
23
|
+
const [firstName, lastName] = data.name.split(' ');
|
|
24
|
+
return {
|
|
25
|
+
id: data.id,
|
|
26
|
+
email: data.email,
|
|
27
|
+
firstName,
|
|
28
|
+
lastName
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const oauth2Google: (server: import("../..").Server) => Promise<void>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oauth2Google = void 0;
|
|
4
|
+
const common_1 = require("@appweaver/common");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
const create_oauth2_plugin_1 = require("./create-oauth2-plugin");
|
|
7
|
+
exports.oauth2Google = (0, create_oauth2_plugin_1.createOAuth2Plugin)(common_1.AuthSource.OAuth2Google, {
|
|
8
|
+
enabled: common_1.config.SECURITY_OAUTH2_GOOGLE_ENABLED,
|
|
9
|
+
clientId: common_1.config.SECURITY_OAUTH2_GOOGLE_CLIENT_ID,
|
|
10
|
+
clientSecret: common_1.config.SECURITY_OAUTH2_GOOGLE_CLIENT_SECRET,
|
|
11
|
+
scope: ['profile', 'email'],
|
|
12
|
+
extractUserInfo: (accessToken) => fetchGoogleUser(accessToken)
|
|
13
|
+
});
|
|
14
|
+
async function fetchGoogleUser(accessToken) {
|
|
15
|
+
const params = new URLSearchParams();
|
|
16
|
+
params.append('access_token', accessToken);
|
|
17
|
+
const resp = await fetch(`${common_1.config.SECURITY_OAUTH2_GOOGLE_USER_INFO_URL}?${params}`, { method: 'GET' });
|
|
18
|
+
if (!resp.ok) {
|
|
19
|
+
throw new errors_1.HttpError(`Google API error: ${resp.status} ${resp.statusText}`, 500);
|
|
20
|
+
}
|
|
21
|
+
const data = await resp.json();
|
|
22
|
+
return {
|
|
23
|
+
id: data.id,
|
|
24
|
+
email: data.email,
|
|
25
|
+
firstName: data.given_name,
|
|
26
|
+
lastName: data.family_name
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RouteSchema } from '@appweaver/common';
|
|
2
|
+
export declare const OAuth2RedirectQuery: import("@sinclair/typebox").TObject<{
|
|
3
|
+
redirectToUrl: import("@sinclair/typebox").TString;
|
|
4
|
+
}>;
|
|
5
|
+
export declare const OAuth2CallbackQuery: import("@sinclair/typebox").TObject<{
|
|
6
|
+
code: import("@sinclair/typebox").TString;
|
|
7
|
+
state: import("@sinclair/typebox").TString;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function createOAuth2RedirectSchema(providerName: string): RouteSchema;
|
|
10
|
+
export declare function createOAuth2CallbackSchema(providerName: string): RouteSchema;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OAuth2CallbackQuery = exports.OAuth2RedirectQuery = void 0;
|
|
4
|
+
exports.createOAuth2RedirectSchema = createOAuth2RedirectSchema;
|
|
5
|
+
exports.createOAuth2CallbackSchema = createOAuth2CallbackSchema;
|
|
6
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
7
|
+
const errors_1 = require("../../errors");
|
|
8
|
+
exports.OAuth2RedirectQuery = typebox_1.Type.Object({
|
|
9
|
+
redirectToUrl: typebox_1.Type.String({
|
|
10
|
+
format: 'uri',
|
|
11
|
+
description: 'A URL to redirect to with one-time-token after successful' +
|
|
12
|
+
' authentication. The client then needs to exchange this token for' +
|
|
13
|
+
' an JWT access token',
|
|
14
|
+
example: 'https://example.com/login/handler'
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
exports.OAuth2CallbackQuery = typebox_1.Type.Object({
|
|
18
|
+
code: typebox_1.Type.String({
|
|
19
|
+
description: 'Authorization code from OAuth2 provider',
|
|
20
|
+
example: '3b7bdc9982feac0e20cf4ddc9be52a1a027142e25b4d14c1b5a280595bc20'
|
|
21
|
+
}),
|
|
22
|
+
state: typebox_1.Type.String({
|
|
23
|
+
description: 'Authorization state returned from OAuth2 provider',
|
|
24
|
+
example: '89bbb34d76801fcf8251193a02a1d62c7c87a'
|
|
25
|
+
})
|
|
26
|
+
});
|
|
27
|
+
function createOAuth2RedirectSchema(providerName) {
|
|
28
|
+
return {
|
|
29
|
+
tags: ['Auth'],
|
|
30
|
+
summary: `Redirect to ${providerName} authentication page`,
|
|
31
|
+
description: `Redirect to ${providerName} authentication page`,
|
|
32
|
+
querystring: exports.OAuth2RedirectQuery,
|
|
33
|
+
response: {
|
|
34
|
+
302: {
|
|
35
|
+
description: `Redirect to ${providerName} authentication page`
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function createOAuth2CallbackSchema(providerName) {
|
|
41
|
+
return {
|
|
42
|
+
tags: ['Auth'],
|
|
43
|
+
summary: `Authenticate identity from ${providerName} callback`,
|
|
44
|
+
description: `Authenticate identity from ${providerName} callback`,
|
|
45
|
+
querystring: exports.OAuth2CallbackQuery,
|
|
46
|
+
response: {
|
|
47
|
+
302: {
|
|
48
|
+
description: `Redirect to 'redirectToUrl' provided when initiating OAuth2 authentication`
|
|
49
|
+
},
|
|
50
|
+
...errors_1.AllErrorResponses
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./recaptcha"), exports);
|
|
18
|
+
__exportStar(require("./recaptcha-verify"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function recaptchaVerify(token: string, remoteIp?: string, action?: string): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recaptchaVerify = recaptchaVerify;
|
|
4
|
+
const common_1 = require("@appweaver/common");
|
|
5
|
+
const errors_1 = require("../../errors");
|
|
6
|
+
async function recaptchaVerify(token, remoteIp, action) {
|
|
7
|
+
const params = new URLSearchParams();
|
|
8
|
+
params.set('secret', common_1.config.SECURITY_RECAPTCHA_SECRET);
|
|
9
|
+
params.set('response', token);
|
|
10
|
+
if (remoteIp) {
|
|
11
|
+
params.set('remoteip', remoteIp);
|
|
12
|
+
}
|
|
13
|
+
const resp = await fetch(common_1.config.SECURITY_RECAPTCHA_VERIFY_URL, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
16
|
+
body: params.toString()
|
|
17
|
+
});
|
|
18
|
+
if (!resp.ok) {
|
|
19
|
+
common_1.logger.error(`reCAPTCHA request failed: ${resp.statusText}`);
|
|
20
|
+
throw new errors_1.HttpError('reCAPTCHA request failed', 500);
|
|
21
|
+
}
|
|
22
|
+
const data = await resp.json();
|
|
23
|
+
common_1.logger.debug(data, 'reCAPTCHA verified');
|
|
24
|
+
if (!data.success) {
|
|
25
|
+
throw new errors_1.HttpError('reCAPTCHA invalid token', 400);
|
|
26
|
+
}
|
|
27
|
+
if (action && data.action !== action) {
|
|
28
|
+
throw new errors_1.HttpError('reCAPTCHA action mismatch', 403);
|
|
29
|
+
}
|
|
30
|
+
if (data.score < common_1.config.SECURITY_RECAPTCHA_MIN_SCORE) {
|
|
31
|
+
throw new errors_1.HttpError('reCAPTCHA low score', 403);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.recaptcha = void 0;
|
|
7
|
+
const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
|
|
8
|
+
const common_1 = require("@appweaver/common");
|
|
9
|
+
const errors_1 = require("../../errors");
|
|
10
|
+
const recaptcha_verify_1 = require("./recaptcha-verify");
|
|
11
|
+
exports.recaptcha = (0, fastify_plugin_1.default)(async (server) => {
|
|
12
|
+
if (!common_1.config.SECURITY_RECAPTCHA_SECRET) {
|
|
13
|
+
throw Error('reCAPTCHA secret is not set');
|
|
14
|
+
}
|
|
15
|
+
server.decorate('recaptcha', async (request) => {
|
|
16
|
+
const token = request.headers[common_1.config.SECURITY_RECAPTCHA_HEADER_NAME.toLowerCase()];
|
|
17
|
+
if (!token) {
|
|
18
|
+
throw new errors_1.HttpError(`Missing reCAPTCHA header: ${common_1.config.SECURITY_RECAPTCHA_HEADER_NAME}`, 401);
|
|
19
|
+
}
|
|
20
|
+
await (0, recaptcha_verify_1.recaptchaVerify)(String(token).trim(), request.ip, request.routeOptions.config.recaptchaAction);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@appweaver/common");
|
|
4
|
+
const factory_1 = require("../../../factory");
|
|
5
|
+
const helper_1 = require("../../helper");
|
|
6
|
+
const authModel = (0, helper_1.resourceAuthModel)();
|
|
7
|
+
const shouldCreateModel = common_1.config.SECURITY_API_KEY_ENABLED ||
|
|
8
|
+
common_1.config.SECURITY_API_KEY_KEEP_DATABASE_TABLE;
|
|
9
|
+
exports.default = shouldCreateModel
|
|
10
|
+
? (0, factory_1.createModel)({
|
|
11
|
+
name: 'ApiKey',
|
|
12
|
+
scalars: {
|
|
13
|
+
key: {
|
|
14
|
+
type: 'string'
|
|
15
|
+
},
|
|
16
|
+
keyHash: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
unique: true,
|
|
19
|
+
hidden: true
|
|
20
|
+
},
|
|
21
|
+
name: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
required: false,
|
|
24
|
+
maxLength: 255
|
|
25
|
+
},
|
|
26
|
+
description: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
required: false
|
|
29
|
+
},
|
|
30
|
+
enabled: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
default: true
|
|
33
|
+
},
|
|
34
|
+
expiresAt: {
|
|
35
|
+
type: 'dateTime',
|
|
36
|
+
required: false
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
...(authModel
|
|
40
|
+
? {
|
|
41
|
+
relations: {
|
|
42
|
+
[(0, common_1.uncapitalize)(authModel.name)]: {
|
|
43
|
+
model: authModel.name,
|
|
44
|
+
mappedBy: 'apiKeys',
|
|
45
|
+
owner: true,
|
|
46
|
+
input: {
|
|
47
|
+
type: 'none'
|
|
48
|
+
},
|
|
49
|
+
output: {
|
|
50
|
+
type: 'none'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
: {}),
|
|
56
|
+
create: {
|
|
57
|
+
omit: ['key']
|
|
58
|
+
},
|
|
59
|
+
update: {
|
|
60
|
+
omit: ['key', 'expiresAt']
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
: undefined;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@appweaver/common");
|
|
4
|
+
const factory_1 = require("../../../factory");
|
|
5
|
+
const helper_1 = require("../../helper");
|
|
6
|
+
function authModelField() {
|
|
7
|
+
return (0, common_1.uncapitalize)((0, helper_1.resourceAuthModel)().name);
|
|
8
|
+
}
|
|
9
|
+
exports.default = common_1.config.SECURITY_API_KEY_ENABLED
|
|
10
|
+
? (0, factory_1.createPolicy)({
|
|
11
|
+
modelName: 'ApiKey',
|
|
12
|
+
checkAccess: (action, resource) => {
|
|
13
|
+
const authFieldName = authModelField();
|
|
14
|
+
const currentAuthId = (0, helper_1.currentAuthUser)().id;
|
|
15
|
+
if (action === 'create') {
|
|
16
|
+
return resource[authFieldName].id === currentAuthId;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
return resource[`${authFieldName}Id`] === currentAuthId;
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
readRestrictions: () => {
|
|
23
|
+
return { [authModelField()]: { id: (0, helper_1.currentAuthUser)().id } };
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
: undefined;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@appweaver/common");
|
|
4
|
+
const factory_1 = require("../../../factory");
|
|
5
|
+
exports.default = common_1.config.SECURITY_API_KEY_ENABLED
|
|
6
|
+
? (0, factory_1.createRoutes)({
|
|
7
|
+
modelName: 'ApiKey',
|
|
8
|
+
aggregate: {
|
|
9
|
+
exclude: true
|
|
10
|
+
},
|
|
11
|
+
export: {
|
|
12
|
+
exclude: true
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
: undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@appweaver/common");
|
|
4
|
+
const factory_1 = require("../../../factory");
|
|
5
|
+
const helper_1 = require("../../helper");
|
|
6
|
+
const context_1 = require("../../../context");
|
|
7
|
+
exports.default = common_1.config.SECURITY_API_KEY_ENABLED
|
|
8
|
+
? (0, factory_1.createService)({
|
|
9
|
+
modelName: 'ApiKey',
|
|
10
|
+
beforeCreate: (data) => {
|
|
11
|
+
data.key = (0, common_1.randomString)(64, { special: false });
|
|
12
|
+
data.keyHash = (0, common_1.makeHash)(data.key);
|
|
13
|
+
// Add relation to the current user when creating a new API Key
|
|
14
|
+
data[(0, common_1.uncapitalize)((0, helper_1.resourceAuthModel)().name)] = {
|
|
15
|
+
id: (0, helper_1.currentAuthUser)().id
|
|
16
|
+
};
|
|
17
|
+
// Enforces max API key duration based on config value
|
|
18
|
+
const maxDuration = common_1.config.SECURITY_API_KEY_MAX_DURATION;
|
|
19
|
+
if (maxDuration) {
|
|
20
|
+
const maxExpiryDate = new Date(Date.now() + maxDuration * 1000);
|
|
21
|
+
if (!data.expiresAt ||
|
|
22
|
+
new Date(data.expiresAt).getTime() > maxExpiryDate.getTime()) {
|
|
23
|
+
data.expiresAt = maxExpiryDate;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
afterCreate: async (data) => {
|
|
28
|
+
const service = (0, context_1.injectService)('ApiKey');
|
|
29
|
+
await service.update(data.id, { key: `...${data.key.slice(-6)}` });
|
|
30
|
+
data.key = `${data.id}${common_1.config.SECURITY_API_KEY_DELIMITER}${data.key}`;
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
: undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@appweaver/common");
|
|
4
|
+
const factory_1 = require("../../../factory");
|
|
5
|
+
const shouldCreateModel = common_1.config.SECURITY_STORE_PROVIDER ===
|
|
6
|
+
'@appweaver/core/security/store/database-security-store' ||
|
|
7
|
+
common_1.config.SECURITY_STORE_KEEP_DATABASE_TABLE;
|
|
8
|
+
exports.default = shouldCreateModel
|
|
9
|
+
? (0, factory_1.createModel)({
|
|
10
|
+
name: 'OneTimeToken',
|
|
11
|
+
audit: {
|
|
12
|
+
createdById: false
|
|
13
|
+
},
|
|
14
|
+
scalars: {
|
|
15
|
+
tokenHash: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
maxLength: 511
|
|
18
|
+
},
|
|
19
|
+
purpose: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
maxLength: 255
|
|
22
|
+
},
|
|
23
|
+
expiresAt: {
|
|
24
|
+
type: 'dateTime'
|
|
25
|
+
},
|
|
26
|
+
data: {
|
|
27
|
+
type: 'json'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
index: [['tokenHash', 'purpose']]
|
|
31
|
+
})
|
|
32
|
+
: undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const factory_1 = require("../../../factory");
|
|
4
|
+
exports.default = (0, factory_1.createModel)({
|
|
5
|
+
name: 'Permission',
|
|
6
|
+
scalars: {
|
|
7
|
+
name: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
unique: true,
|
|
10
|
+
maxLength: 255
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
read: {
|
|
14
|
+
omit: ['updatedAt', 'createdAt', 'createdById']
|
|
15
|
+
}
|
|
16
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const factory_1 = require("../../../factory");
|
|
4
|
+
exports.default = (0, factory_1.createModel)({
|
|
5
|
+
name: 'Role',
|
|
6
|
+
scalars: {
|
|
7
|
+
name: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
unique: true,
|
|
10
|
+
maxLength: 255
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
relations: {
|
|
14
|
+
permissions: {
|
|
15
|
+
model: 'Permission',
|
|
16
|
+
array: true
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
read: {
|
|
20
|
+
omit: ['updatedAt', 'createdAt', 'createdById']
|
|
21
|
+
}
|
|
22
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SecurityStore, ValidationResult } from '@appweaver/common';
|
|
2
|
+
export declare class DatabaseSecurityStore extends SecurityStore {
|
|
3
|
+
generateOneTimeToken<T = any>(purpose: string, data: T, ttl: number): Promise<string>;
|
|
4
|
+
useOneTimeToken<T = any>(token: string, purpose: string, validateContent?: (value: T) => ValidationResult): Promise<T>;
|
|
5
|
+
}
|