mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 04:26:11 +00:00
implemented comments
This commit is contained in:
+2
-2
@@ -70,6 +70,6 @@ STRIPE_PRODUCT_TEAM=
|
|||||||
STRIPE_PRODUCT_PRO=
|
STRIPE_PRODUCT_PRO=
|
||||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
|
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
|
||||||
|
|
||||||
GOOGLE_CLIENT_ID=
|
CLIENT_ID_GOOGLE=
|
||||||
GOOGLE_CLIENT_SECRET=
|
CLIENT_SECRET_GOOGLE=
|
||||||
SESSION_SECRET=
|
SESSION_SECRET=
|
||||||
|
|||||||
@@ -29,12 +29,14 @@ export const getClientIdVercel = async () => (await client.getSecret('CLIENT_ID_
|
|||||||
export const getClientIdNetlify = async () => (await client.getSecret('CLIENT_ID_NETLIFY')).secretValue;
|
export const getClientIdNetlify = async () => (await client.getSecret('CLIENT_ID_NETLIFY')).secretValue;
|
||||||
export const getClientIdGitHub = async () => (await client.getSecret('CLIENT_ID_GITHUB')).secretValue;
|
export const getClientIdGitHub = async () => (await client.getSecret('CLIENT_ID_GITHUB')).secretValue;
|
||||||
export const getClientIdGitLab = async () => (await client.getSecret('CLIENT_ID_GITLAB')).secretValue;
|
export const getClientIdGitLab = async () => (await client.getSecret('CLIENT_ID_GITLAB')).secretValue;
|
||||||
|
export const getClientIdGoogle = async () => (await client.getSecret('CLIENT_ID_GOOGLE')).secretValue;
|
||||||
export const getClientSecretAzure = async () => (await client.getSecret('CLIENT_SECRET_AZURE')).secretValue;
|
export const getClientSecretAzure = async () => (await client.getSecret('CLIENT_SECRET_AZURE')).secretValue;
|
||||||
export const getClientSecretHeroku = async () => (await client.getSecret('CLIENT_SECRET_HEROKU')).secretValue;
|
export const getClientSecretHeroku = async () => (await client.getSecret('CLIENT_SECRET_HEROKU')).secretValue;
|
||||||
export const getClientSecretVercel = async () => (await client.getSecret('CLIENT_SECRET_VERCEL')).secretValue;
|
export const getClientSecretVercel = async () => (await client.getSecret('CLIENT_SECRET_VERCEL')).secretValue;
|
||||||
export const getClientSecretNetlify = async () => (await client.getSecret('CLIENT_SECRET_NETLIFY')).secretValue;
|
export const getClientSecretNetlify = async () => (await client.getSecret('CLIENT_SECRET_NETLIFY')).secretValue;
|
||||||
export const getClientSecretGitHub = async () => (await client.getSecret('CLIENT_SECRET_GITHUB')).secretValue;
|
export const getClientSecretGitHub = async () => (await client.getSecret('CLIENT_SECRET_GITHUB')).secretValue;
|
||||||
export const getClientSecretGitLab = async () => (await client.getSecret('CLIENT_SECRET_GITLAB')).secretValue;
|
export const getClientSecretGitLab = async () => (await client.getSecret('CLIENT_SECRET_GITLAB')).secretValue;
|
||||||
|
export const getClientSecretGoogle = async () => (await client.getSecret('CLIENT_SECRET_GOOGLE')).secretValue;
|
||||||
export const getClientSlugVercel = async () => (await client.getSecret('CLIENT_SLUG_VERCEL')).secretValue;
|
export const getClientSlugVercel = async () => (await client.getSecret('CLIENT_SLUG_VERCEL')).secretValue;
|
||||||
export const getPostHogHost = async () => (await client.getSecret('POSTHOG_HOST')).secretValue || 'https://app.posthog.com';
|
export const getPostHogHost = async () => (await client.getSecret('POSTHOG_HOST')).secretValue || 'https://app.posthog.com';
|
||||||
export const getPostHogProjectApiKey = async () => (await client.getSecret('POSTHOG_PROJECT_API_KEY')).secretValue || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE';
|
export const getPostHogProjectApiKey = async () => (await client.getSecret('POSTHOG_PROJECT_API_KEY')).secretValue || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE';
|
||||||
|
|||||||
@@ -267,7 +267,3 @@ export const getNewToken = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const handleGoogleCallback = (req: Request, res: Response) => {
|
|
||||||
res.redirect(`/login/provider/success?token=${encodeURIComponent(req.providerAuthToken)}`);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import * as integrationController from './integrationController';
|
|||||||
import * as keyController from './keyController';
|
import * as keyController from './keyController';
|
||||||
import * as membershipController from './membershipController';
|
import * as membershipController from './membershipController';
|
||||||
import * as membershipOrgController from './membershipOrgController';
|
import * as membershipOrgController from './membershipOrgController';
|
||||||
|
import * as oauthController from './oauthController';
|
||||||
import * as organizationController from './organizationController';
|
import * as organizationController from './organizationController';
|
||||||
import * as passwordController from './passwordController';
|
import * as passwordController from './passwordController';
|
||||||
import * as secretController from './secretController';
|
import * as secretController from './secretController';
|
||||||
@@ -23,6 +24,7 @@ export {
|
|||||||
keyController,
|
keyController,
|
||||||
membershipController,
|
membershipController,
|
||||||
membershipOrgController,
|
membershipOrgController,
|
||||||
|
oauthController,
|
||||||
organizationController,
|
organizationController,
|
||||||
passwordController,
|
passwordController,
|
||||||
secretController,
|
secretController,
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { Request, Response } from 'express';
|
||||||
|
|
||||||
|
export const handleAuthProviderCallback = (req: Request, res: Response) => {
|
||||||
|
res.redirect(`/login/provider/success?token=${encodeURIComponent(req.providerAuthToken)}`);
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import * as Sentry from '@sentry/node';
|
|||||||
import * as bigintConversion from 'bigint-conversion';
|
import * as bigintConversion from 'bigint-conversion';
|
||||||
const jsrp = require('jsrp');
|
const jsrp = require('jsrp');
|
||||||
import { User, LoginSRPDetail } from '../../models';
|
import { User, LoginSRPDetail } from '../../models';
|
||||||
import { issueAuthTokens, createToken } from '../../helpers/auth';
|
import { issueAuthTokens, createToken, validateProviderAuthToken } from '../../helpers/auth';
|
||||||
import { checkUserDevice } from '../../helpers/user';
|
import { checkUserDevice } from '../../helpers/user';
|
||||||
import { sendMail } from '../../helpers/nodemailer';
|
import { sendMail } from '../../helpers/nodemailer';
|
||||||
import { TokenService } from '../../services';
|
import { TokenService } from '../../services';
|
||||||
@@ -20,12 +20,14 @@ import {
|
|||||||
getJwtMfaLifetime,
|
getJwtMfaLifetime,
|
||||||
getJwtMfaSecret,
|
getJwtMfaSecret,
|
||||||
getHttpsEnabled,
|
getHttpsEnabled,
|
||||||
getJwtProviderAuthSecret
|
|
||||||
} from '../../config';
|
} from '../../config';
|
||||||
|
import { AuthProvider } from '../../models/user';
|
||||||
|
|
||||||
declare module 'jsonwebtoken' {
|
declare module 'jsonwebtoken' {
|
||||||
export interface ProviderAuthJwtPayload extends jwt.JwtPayload {
|
export interface ProviderAuthJwtPayload extends jwt.JwtPayload {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
authProvider: AuthProvider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,30 +44,25 @@ export const login1 = async (req: Request, res: Response) => {
|
|||||||
providerAuthToken,
|
providerAuthToken,
|
||||||
clientPublicKey
|
clientPublicKey
|
||||||
}: {
|
}: {
|
||||||
email?: string;
|
email: string;
|
||||||
clientPublicKey: string,
|
clientPublicKey: string,
|
||||||
providerAuthToken?: string;
|
providerAuthToken?: string;
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
let userId = '';
|
const user = await User.findOne({
|
||||||
if (providerAuthToken) {
|
|
||||||
const decodedToken = <jwt.ProviderAuthJwtPayload>(
|
|
||||||
jwt.verify(providerAuthToken, await getJwtProviderAuthSecret())
|
|
||||||
);
|
|
||||||
|
|
||||||
userId = decodedToken.userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filter = userId ? {
|
|
||||||
_id: userId,
|
|
||||||
} : {
|
|
||||||
email,
|
email,
|
||||||
}
|
}).select('+salt +verifier');
|
||||||
|
|
||||||
const user = await User.findOne(filter).select('+salt +verifier');
|
|
||||||
|
|
||||||
if (!user) throw new Error('Failed to find user');
|
if (!user) throw new Error('Failed to find user');
|
||||||
|
|
||||||
|
if (user.authProvider) {
|
||||||
|
await validateProviderAuthToken({
|
||||||
|
email,
|
||||||
|
user,
|
||||||
|
providerAuthToken,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const server = new jsrp.server();
|
const server = new jsrp.server();
|
||||||
server.init(
|
server.init(
|
||||||
{
|
{
|
||||||
@@ -75,14 +72,10 @@ export const login1 = async (req: Request, res: Response) => {
|
|||||||
async () => {
|
async () => {
|
||||||
// generate server-side public key
|
// generate server-side public key
|
||||||
const serverPublicKey = server.getPublicKey();
|
const serverPublicKey = server.getPublicKey();
|
||||||
const identifier = userId ? {
|
await LoginSRPDetail.findOneAndReplace({
|
||||||
userId,
|
userId: user.id,
|
||||||
} : {
|
}, {
|
||||||
email,
|
userId: user.id,
|
||||||
}
|
|
||||||
|
|
||||||
await LoginSRPDetail.findOneAndReplace(filter, {
|
|
||||||
...identifier,
|
|
||||||
clientPublicKey: clientPublicKey,
|
clientPublicKey: clientPublicKey,
|
||||||
serverBInt: bigintConversion.bigintToBuf(server.bInt),
|
serverBInt: bigintConversion.bigintToBuf(server.bInt),
|
||||||
}, { upsert: true, returnNewDocument: false });
|
}, { upsert: true, returnNewDocument: false });
|
||||||
@@ -115,32 +108,22 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
if (!req.headers['user-agent']) throw InternalServerError({ message: 'User-Agent header is required' });
|
if (!req.headers['user-agent']) throw InternalServerError({ message: 'User-Agent header is required' });
|
||||||
|
|
||||||
const { email, clientProof, providerAuthToken } = req.body;
|
const { email, clientProof, providerAuthToken } = req.body;
|
||||||
|
|
||||||
let userId = '';
|
|
||||||
if (providerAuthToken) {
|
|
||||||
const decodedToken = <jwt.ProviderAuthJwtPayload>(
|
|
||||||
jwt.verify(providerAuthToken, await getJwtProviderAuthSecret())
|
|
||||||
);
|
|
||||||
userId = decodedToken.userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filter = userId ? {
|
const user = await User.findOne({
|
||||||
_id: userId,
|
|
||||||
} : {
|
|
||||||
email,
|
email,
|
||||||
}
|
}).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag');
|
||||||
|
|
||||||
const user = await User.findOne(filter).select('+salt +verifier +encryptionVersion +protectedKey +protectedKeyIV +protectedKeyTag +publicKey +encryptedPrivateKey +iv +tag');
|
|
||||||
|
|
||||||
if (!user) throw new Error('Failed to find user');
|
if (!user) throw new Error('Failed to find user');
|
||||||
|
|
||||||
const identifier = userId ? {
|
if (user.authProvider) {
|
||||||
userId,
|
await validateProviderAuthToken({
|
||||||
} : {
|
email,
|
||||||
email,
|
user,
|
||||||
|
providerAuthToken,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginSRPDetail = await LoginSRPDetail.findOneAndDelete({ ...identifier });
|
const loginSRPDetail = await LoginSRPDetail.findOneAndDelete({ userId: user.id });
|
||||||
|
|
||||||
if (!loginSRPDetail) {
|
if (!loginSRPDetail) {
|
||||||
return BadRequestError(Error("Failed to find login details for SRP"))
|
return BadRequestError(Error("Failed to find login details for SRP"))
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
getJwtAuthLifetime,
|
getJwtAuthLifetime,
|
||||||
getJwtAuthSecret,
|
getJwtAuthSecret,
|
||||||
|
getJwtProviderAuthSecret,
|
||||||
getJwtRefreshLifetime,
|
getJwtRefreshLifetime,
|
||||||
getJwtRefreshSecret
|
getJwtRefreshSecret
|
||||||
} from '../config';
|
} from '../config';
|
||||||
@@ -319,8 +320,34 @@ const createToken = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validateProviderAuthToken = async ({
|
||||||
|
email,
|
||||||
|
user,
|
||||||
|
providerAuthToken,
|
||||||
|
}: {
|
||||||
|
email: string;
|
||||||
|
user: IUser,
|
||||||
|
providerAuthToken?: string;
|
||||||
|
}) => {
|
||||||
|
if (!providerAuthToken) {
|
||||||
|
throw new Error('Invalid authentication request.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const decodedToken = <jwt.ProviderAuthJwtPayload>(
|
||||||
|
jwt.verify(providerAuthToken, await getJwtProviderAuthSecret())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
decodedToken.authProvider !== user.authProvider ||
|
||||||
|
decodedToken.email !== email
|
||||||
|
) {
|
||||||
|
throw new Error('Invalid authentication credentials.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
validateAuthMode,
|
validateAuthMode,
|
||||||
|
validateProviderAuthToken,
|
||||||
getAuthUserPayload,
|
getAuthUserPayload,
|
||||||
getAuthSTDPayload,
|
getAuthSTDPayload,
|
||||||
getAuthSAAKPayload,
|
getAuthSAAKPayload,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import {
|
|||||||
membership as v1MembershipRouter,
|
membership as v1MembershipRouter,
|
||||||
key as v1KeyRouter,
|
key as v1KeyRouter,
|
||||||
inviteOrg as v1InviteOrgRouter,
|
inviteOrg as v1InviteOrgRouter,
|
||||||
|
oauth as v1OAuth,
|
||||||
user as v1UserRouter,
|
user as v1UserRouter,
|
||||||
userAction as v1UserActionRouter,
|
userAction as v1UserActionRouter,
|
||||||
secret as v1SecretRouter,
|
secret as v1SecretRouter,
|
||||||
@@ -78,6 +79,7 @@ import {
|
|||||||
getSiteURL,
|
getSiteURL,
|
||||||
getSessionSecret,
|
getSessionSecret,
|
||||||
} from './config';
|
} from './config';
|
||||||
|
import { initializePassport } from './utils/auth';
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
TelemetryService.logTelemetryMessage();
|
TelemetryService.logTelemetryMessage();
|
||||||
@@ -95,6 +97,9 @@ const main = async () => {
|
|||||||
|
|
||||||
patchRouterParam();
|
patchRouterParam();
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
await initializePassport();
|
||||||
|
|
||||||
app.enable('trust proxy');
|
app.enable('trust proxy');
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
@@ -129,6 +134,7 @@ const main = async () => {
|
|||||||
// v1 routes (default)
|
// v1 routes (default)
|
||||||
app.use('/api/v1/signup', v1SignupRouter);
|
app.use('/api/v1/signup', v1SignupRouter);
|
||||||
app.use('/api/v1/auth', v1AuthRouter);
|
app.use('/api/v1/auth', v1AuthRouter);
|
||||||
|
app.use('/api/v1/oauth', v1OAuth);
|
||||||
app.use('/api/v1/bot', v1BotRouter);
|
app.use('/api/v1/bot', v1BotRouter);
|
||||||
app.use('/api/v1/user', v1UserRouter);
|
app.use('/api/v1/user', v1UserRouter);
|
||||||
app.use('/api/v1/user-action', v1UserActionRouter);
|
app.use('/api/v1/user-action', v1UserActionRouter);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import ServiceAccountKey, { IServiceAccountKey } from './serviceAccountKey'; //
|
|||||||
import ServiceAccountOrganizationPermission, { IServiceAccountOrganizationPermission } from './serviceAccountOrganizationPermission'; // new
|
import ServiceAccountOrganizationPermission, { IServiceAccountOrganizationPermission } from './serviceAccountOrganizationPermission'; // new
|
||||||
import ServiceAccountWorkspacePermission, { IServiceAccountWorkspacePermission } from './serviceAccountWorkspacePermission'; // new
|
import ServiceAccountWorkspacePermission, { IServiceAccountWorkspacePermission } from './serviceAccountWorkspacePermission'; // new
|
||||||
import TokenData, { ITokenData } from './tokenData';
|
import TokenData, { ITokenData } from './tokenData';
|
||||||
import User, { IUser } from './user';
|
import User,{ AuthProvider, IUser } from './user';
|
||||||
import UserAction, { IUserAction } from './userAction';
|
import UserAction, { IUserAction } from './userAction';
|
||||||
import Workspace, { IWorkspace } from './workspace';
|
import Workspace, { IWorkspace } from './workspace';
|
||||||
import ServiceTokenData, { IServiceTokenData } from './serviceTokenData';
|
import ServiceTokenData, { IServiceTokenData } from './serviceTokenData';
|
||||||
@@ -24,6 +24,7 @@ import APIKeyData, { IAPIKeyData } from './apiKeyData';
|
|||||||
import LoginSRPDetail, { ILoginSRPDetail } from './loginSRPDetail';
|
import LoginSRPDetail, { ILoginSRPDetail } from './loginSRPDetail';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
AuthProvider,
|
||||||
BackupPrivateKey,
|
BackupPrivateKey,
|
||||||
IBackupPrivateKey,
|
IBackupPrivateKey,
|
||||||
Bot,
|
Bot,
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import { Schema, model, Types, Document } from 'mongoose';
|
import { Schema, model, Types, Document } from 'mongoose';
|
||||||
|
|
||||||
|
export enum AuthProvider {
|
||||||
|
GOOGLE = 'google',
|
||||||
|
}
|
||||||
|
|
||||||
export interface IUser extends Document {
|
export interface IUser extends Document {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
authId?: string;
|
authId?: string;
|
||||||
authProvider?: string;
|
authProvider?: AuthProvider;
|
||||||
email: string;
|
email: string;
|
||||||
firstName?: string;
|
firstName?: string;
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
@@ -33,6 +37,7 @@ const userSchema = new Schema<IUser>(
|
|||||||
},
|
},
|
||||||
authProvider: {
|
authProvider: {
|
||||||
type: String,
|
type: String,
|
||||||
|
enum: AuthProvider,
|
||||||
},
|
},
|
||||||
email: {
|
email: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@@ -1,50 +1,10 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
import { body } from 'express-validator';
|
import { body } from 'express-validator';
|
||||||
import passport from 'passport';
|
|
||||||
import { requireAuth, validateRequest } from '../../middleware';
|
import { requireAuth, validateRequest } from '../../middleware';
|
||||||
import { authController } from '../../controllers/v1';
|
import { authController } from '../../controllers/v1';
|
||||||
import { authLimiter } from '../../helpers/rateLimiter';
|
import { authLimiter } from '../../helpers/rateLimiter';
|
||||||
import { AUTH_MODE_JWT } from '../../variables';
|
import { AUTH_MODE_JWT } from '../../variables';
|
||||||
import { User } from '../../models';
|
|
||||||
import { createToken } from '../../helpers/auth';
|
|
||||||
import { getJwtProviderAuthLifetime, getJwtProviderAuthSecret } from '../../config';
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
||||||
const GoogleStrategy = require('passport-google-oidc');
|
|
||||||
|
|
||||||
passport.use(new GoogleStrategy({
|
|
||||||
passReqToCallback: true,
|
|
||||||
clientID: process.env['GOOGLE_CLIENT_ID'],
|
|
||||||
clientSecret: process.env['GOOGLE_CLIENT_SECRET'],
|
|
||||||
callbackURL: '/api/v1/auth/google/callback',
|
|
||||||
}, async (req: express.Request, issuer: any, profile: any, cb: any) => {
|
|
||||||
const email = profile.emails[0].value;
|
|
||||||
let user = await User.findOne({
|
|
||||||
authProvider: issuer,
|
|
||||||
authId: profile.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
user = await new User({
|
|
||||||
email,
|
|
||||||
authProvider: issuer,
|
|
||||||
authId: profile.id,
|
|
||||||
}).save();
|
|
||||||
}
|
|
||||||
|
|
||||||
const providerAuthToken = createToken({
|
|
||||||
payload: {
|
|
||||||
userId: user._id.toString(),
|
|
||||||
email: user.email,
|
|
||||||
},
|
|
||||||
expiresIn: await getJwtProviderAuthLifetime(),
|
|
||||||
secret: await getJwtProviderAuthSecret(),
|
|
||||||
});
|
|
||||||
|
|
||||||
req.providerAuthToken = providerAuthToken;
|
|
||||||
cb(null, profile);
|
|
||||||
}));
|
|
||||||
|
|
||||||
router.post('/token', validateRequest, authController.getNewToken);
|
router.post('/token', validateRequest, authController.getNewToken);
|
||||||
|
|
||||||
@@ -83,18 +43,5 @@ router.post(
|
|||||||
authController.checkAuth
|
authController.checkAuth
|
||||||
);
|
);
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/login/google',
|
|
||||||
authLimiter,
|
|
||||||
passport.authenticate('google', {
|
|
||||||
scope: ['profile', 'email'],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/google/callback',
|
|
||||||
passport.authenticate('google', { failureRedirect: '/error', session: false }),
|
|
||||||
authController.handleGoogleCallback,
|
|
||||||
)
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import password from './password';
|
|||||||
import stripe from './stripe';
|
import stripe from './stripe';
|
||||||
import integration from './integration';
|
import integration from './integration';
|
||||||
import integrationAuth from './integrationAuth';
|
import integrationAuth from './integrationAuth';
|
||||||
import secretsFolder from './secretsFolder'
|
import secretsFolder from './secretsFolder';
|
||||||
|
import oauth from './oauth';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
signup,
|
signup,
|
||||||
@@ -29,6 +30,7 @@ export {
|
|||||||
membership,
|
membership,
|
||||||
key,
|
key,
|
||||||
inviteOrg,
|
inviteOrg,
|
||||||
|
oauth,
|
||||||
secret,
|
secret,
|
||||||
serviceToken,
|
serviceToken,
|
||||||
password,
|
password,
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import express from 'express';
|
||||||
|
const router = express.Router();
|
||||||
|
import passport from 'passport';
|
||||||
|
import { oauthController } from '../../controllers/v1';
|
||||||
|
import { authLimiter } from '../../helpers/rateLimiter';
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/redirect/google',
|
||||||
|
authLimiter,
|
||||||
|
passport.authenticate('google', {
|
||||||
|
scope: ['profile', 'email'],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/callback/google',
|
||||||
|
passport.authenticate('google', { failureRedirect: '/error', session: false }),
|
||||||
|
oauthController.handleAuthProviderCallback,
|
||||||
|
)
|
||||||
|
|
||||||
|
export default router;
|
||||||
@@ -1,10 +1,22 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import passport from 'passport';
|
||||||
import { AuthData } from '../interfaces/middleware';
|
import { AuthData } from '../interfaces/middleware';
|
||||||
import {
|
import {
|
||||||
|
AuthProvider,
|
||||||
User,
|
User,
|
||||||
ServiceAccount,
|
ServiceAccount,
|
||||||
ServiceTokenData,
|
ServiceTokenData,
|
||||||
ServiceToken
|
|
||||||
} from '../models';
|
} from '../models';
|
||||||
|
import { createToken } from '../helpers/auth';
|
||||||
|
import {
|
||||||
|
getClientIdGoogle,
|
||||||
|
getClientSecretGoogle,
|
||||||
|
getJwtProviderAuthLifetime,
|
||||||
|
getJwtProviderAuthSecret
|
||||||
|
} from '../config';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const GoogleStrategy = require('passport-google-oidc');
|
||||||
|
|
||||||
// TODO: find a more optimal folder structure to store these types of functions
|
// TODO: find a more optimal folder structure to store these types of functions
|
||||||
|
|
||||||
@@ -48,7 +60,47 @@ const getAuthDataPayloadUserObj = (authData: AuthData) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initializePassport = async () => {
|
||||||
|
const googleClientSecret = await getClientSecretGoogle();
|
||||||
|
const googleClientId = await getClientIdGoogle();
|
||||||
|
|
||||||
|
passport.use(new GoogleStrategy({
|
||||||
|
passReqToCallback: true,
|
||||||
|
clientID: googleClientId,
|
||||||
|
clientSecret: googleClientSecret,
|
||||||
|
callbackURL: '/api/v1/oauth/callback/google',
|
||||||
|
}, async (req: express.Request, issuer: any, profile: any, cb: any) => {
|
||||||
|
const email = profile.emails[0].value;
|
||||||
|
let user = await User.findOne({
|
||||||
|
authProvider: AuthProvider.GOOGLE,
|
||||||
|
authId: profile.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
user = await new User({
|
||||||
|
email,
|
||||||
|
authProvider: AuthProvider.GOOGLE,
|
||||||
|
authId: profile.id,
|
||||||
|
}).save();
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerAuthToken = createToken({
|
||||||
|
payload: {
|
||||||
|
userId: user._id.toString(),
|
||||||
|
email: user.email,
|
||||||
|
authProvider: user.authProvider,
|
||||||
|
},
|
||||||
|
expiresIn: await getJwtProviderAuthLifetime(),
|
||||||
|
secret: await getJwtProviderAuthSecret(),
|
||||||
|
});
|
||||||
|
|
||||||
|
req.providerAuthToken = providerAuthToken;
|
||||||
|
cb(null, profile);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getAuthDataPayloadIdObj,
|
getAuthDataPayloadIdObj,
|
||||||
getAuthDataPayloadUserObj
|
getAuthDataPayloadUserObj,
|
||||||
}
|
initializePassport,
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ export default function Login() {
|
|||||||
const lang = router.locale ?? 'en';
|
const lang = router.locale ?? 'en';
|
||||||
const [isLoginWithEmail, setIsLoginWithEmail] = useState(false);
|
const [isLoginWithEmail, setIsLoginWithEmail] = useState(false);
|
||||||
const {
|
const {
|
||||||
providerAuthToken,
|
providerAuthToken,
|
||||||
userId,
|
userId,
|
||||||
email: providerEmail,
|
email: providerEmail,
|
||||||
setProviderAuthToken
|
setProviderAuthToken
|
||||||
} = useProviderAuth();
|
} = useProviderAuth();
|
||||||
|
|
||||||
const setLanguage = async (to: string) => {
|
const setLanguage = async (to: string) => {
|
||||||
router.push('/login', '/login', { locale: to });
|
router.push('/login', '/login', { locale: to });
|
||||||
localStorage.setItem('lang', to);
|
localStorage.setItem('lang', to);
|
||||||
@@ -51,7 +51,7 @@ export default function Login() {
|
|||||||
redirectToDashboard();
|
redirectToDashboard();
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const renderView = (loginStep: number) => {
|
const renderView = (loginStep: number) => {
|
||||||
|
|
||||||
if (providerAuthToken && step === 1) {
|
if (providerAuthToken && step === 1) {
|
||||||
@@ -83,12 +83,12 @@ export default function Login() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button type='button' className='text-white' onClick={() => {
|
<button type='button' className='text-white' onClick={() => {
|
||||||
window.open('/api/v1/auth/login/google')
|
window.open('/api/v1/oauth/redirect/google')
|
||||||
}}>
|
}}>
|
||||||
Continue with Google
|
Continue with Google
|
||||||
</button>
|
</button>
|
||||||
<button type='button' className='text-white' onClick={() => {
|
<button type='button' className='text-white' onClick={() => {
|
||||||
setIsLoginWithEmail(true);
|
setIsLoginWithEmail(true);
|
||||||
}}>
|
}}>
|
||||||
Continue with Email
|
Continue with Email
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ import UserInfoStep from '@app/components/signup/UserInfoStep';
|
|||||||
import SecurityClient from '@app/components/utilities/SecurityClient';
|
import SecurityClient from '@app/components/utilities/SecurityClient';
|
||||||
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
||||||
import { useFetchServerStatus } from '@app/hooks/api/serverDetails';
|
import { useFetchServerStatus } from '@app/hooks/api/serverDetails';
|
||||||
|
import { useProviderAuth } from '@app/hooks/useProviderAuth';
|
||||||
|
|
||||||
import checkEmailVerificationCode from './api/auth/CheckEmailVerificationCode';
|
import checkEmailVerificationCode from './api/auth/CheckEmailVerificationCode';
|
||||||
import getWorkspaces from './api/workspace/getWorkspaces';
|
import getWorkspaces from './api/workspace/getWorkspaces';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns the signup page
|
* @returns the signup page
|
||||||
*/
|
*/
|
||||||
@@ -31,7 +33,13 @@ export default function SignUp() {
|
|||||||
const [step, setStep] = useState(1);
|
const [step, setStep] = useState(1);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data: serverDetails } = useFetchServerStatus();
|
const { data: serverDetails } = useFetchServerStatus();
|
||||||
|
const [isSignupWithEmail, setIsSignupWithEmail] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { providerAuthToken } = useProviderAuth();
|
||||||
|
|
||||||
|
if (providerAuthToken && step < 3) {
|
||||||
|
setStep(3);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tryAuth = async () => {
|
const tryAuth = async () => {
|
||||||
@@ -60,7 +68,7 @@ export default function SignUp() {
|
|||||||
// Checking if the code matches the email.
|
// Checking if the code matches the email.
|
||||||
const response = await checkEmailVerificationCode({ email, code });
|
const response = await checkEmailVerificationCode({ email, code });
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const {token} = await response.json();
|
const { token } = await response.json();
|
||||||
SecurityClient.setSignupToken(token);
|
SecurityClient.setSignupToken(token);
|
||||||
setStep(3);
|
setStep(3);
|
||||||
} else {
|
} else {
|
||||||
@@ -71,17 +79,83 @@ export default function SignUp() {
|
|||||||
|
|
||||||
// when email service is not configured, skip step 2 and 5
|
// when email service is not configured, skip step 2 and 5
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!serverDetails?.emailConfigured && step === 2){
|
if (!serverDetails?.emailConfigured && step === 2) {
|
||||||
incrementStep()
|
incrementStep()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serverDetails?.emailConfigured && step === 5){
|
if (!serverDetails?.emailConfigured && step === 5) {
|
||||||
getWorkspaces().then((userWorkspaces)=>{
|
getWorkspaces().then((userWorkspaces) => {
|
||||||
router.push(`/dashboard/${userWorkspaces[0]._id}`);
|
router.push(`/dashboard/${userWorkspaces[0]._id}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [step]);
|
}, [step]);
|
||||||
|
|
||||||
|
const renderView = (registerStep: number) => {
|
||||||
|
if (isSignupWithEmail && registerStep === 1) {
|
||||||
|
return <EnterEmailStep email={email} setEmail={setEmail} incrementStep={incrementStep} />
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSignupWithEmail && registerStep === 1) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button type='button' className='text-white' onClick={() => {
|
||||||
|
window.open('/api/v1/auth/login/google')
|
||||||
|
}}>
|
||||||
|
Continue with Google
|
||||||
|
</button>
|
||||||
|
<button type='button' className='text-white' onClick={() => {
|
||||||
|
setIsSignupWithEmail(true);
|
||||||
|
}}>
|
||||||
|
Continue with Email
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registerStep === 2) {
|
||||||
|
return (
|
||||||
|
<CodeInputStep
|
||||||
|
email={email}
|
||||||
|
incrementStep={incrementStep}
|
||||||
|
setCode={setCode}
|
||||||
|
codeError={codeError}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registerStep === 3) {
|
||||||
|
return (
|
||||||
|
<UserInfoStep
|
||||||
|
incrementStep={incrementStep}
|
||||||
|
email={email}
|
||||||
|
password={password}
|
||||||
|
setPassword={setPassword}
|
||||||
|
firstName={firstName}
|
||||||
|
setFirstName={setFirstName}
|
||||||
|
lastName={lastName}
|
||||||
|
setLastName={setLastName}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registerStep === 4) {
|
||||||
|
return (
|
||||||
|
<DownloadBackupPDF
|
||||||
|
incrementStep={incrementStep}
|
||||||
|
email={email}
|
||||||
|
password={password}
|
||||||
|
name={`${firstName} ${lastName}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverDetails?.emailConfigured) {
|
||||||
|
return <TeamInviteStep />
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-bunker-800 h-screen flex flex-col items-center justify-center">
|
<div className="bg-bunker-800 h-screen flex flex-col items-center justify-center">
|
||||||
<Head>
|
<Head>
|
||||||
@@ -98,34 +172,7 @@ export default function SignUp() {
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<form onSubmit={(e) => e.preventDefault()}>
|
<form onSubmit={(e) => e.preventDefault()}>
|
||||||
{step === 1 ? (
|
{renderView(step)}
|
||||||
<EnterEmailStep email={email} setEmail={setEmail} incrementStep={incrementStep} />
|
|
||||||
) : step === 2 ? (
|
|
||||||
<CodeInputStep
|
|
||||||
email={email}
|
|
||||||
incrementStep={incrementStep}
|
|
||||||
setCode={setCode}
|
|
||||||
codeError={codeError}
|
|
||||||
/>
|
|
||||||
) : step === 3 ? (
|
|
||||||
<UserInfoStep
|
|
||||||
incrementStep={incrementStep}
|
|
||||||
email={email}
|
|
||||||
password={password}
|
|
||||||
setPassword={setPassword}
|
|
||||||
firstName={firstName}
|
|
||||||
setFirstName={setFirstName}
|
|
||||||
lastName={lastName}
|
|
||||||
setLastName={setLastName}
|
|
||||||
/>
|
|
||||||
) : step === 4 ? (
|
|
||||||
<DownloadBackupPDF
|
|
||||||
incrementStep={incrementStep}
|
|
||||||
email={email}
|
|
||||||
password={password}
|
|
||||||
name={`${firstName} ${lastName}`}
|
|
||||||
/>
|
|
||||||
) : (serverDetails?.emailConfigured ? <TeamInviteStep /> : "")}
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user