161 lines
5.6 KiB
TypeScript
161 lines
5.6 KiB
TypeScript
|
|
import * as plugins from '../../plugins.ts';
|
||
|
|
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||
|
|
import type { OpsServer } from '../classes.opsserver.ts';
|
||
|
|
import { externalAuthService } from '../../services/external.auth.service.ts';
|
||
|
|
|
||
|
|
export class OAuthHandler {
|
||
|
|
public typedrouter = new plugins.typedrequest.TypedRouter();
|
||
|
|
|
||
|
|
constructor(private opsServerRef: OpsServer) {
|
||
|
|
this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
|
||
|
|
this.registerHandlers();
|
||
|
|
}
|
||
|
|
|
||
|
|
private registerHandlers(): void {
|
||
|
|
// OAuth Authorize - initiate OAuth flow
|
||
|
|
this.typedrouter.addTypedHandler(
|
||
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_OAuthAuthorize>(
|
||
|
|
'oauthAuthorize',
|
||
|
|
async (dataArg) => {
|
||
|
|
try {
|
||
|
|
const { providerId, returnUrl } = dataArg;
|
||
|
|
|
||
|
|
const { authUrl } = await externalAuthService.initiateOAuth(providerId, returnUrl);
|
||
|
|
|
||
|
|
return { redirectUrl: authUrl };
|
||
|
|
} catch (error) {
|
||
|
|
if (error instanceof plugins.typedrequest.TypedResponseError) throw error;
|
||
|
|
const errorMessage = error instanceof Error ? error.message : 'Authorization failed';
|
||
|
|
throw new plugins.typedrequest.TypedResponseError(errorMessage);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
),
|
||
|
|
);
|
||
|
|
|
||
|
|
// OAuth Callback - handle provider callback
|
||
|
|
this.typedrouter.addTypedHandler(
|
||
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_OAuthCallback>(
|
||
|
|
'oauthCallback',
|
||
|
|
async (dataArg) => {
|
||
|
|
try {
|
||
|
|
const { code, state } = dataArg;
|
||
|
|
|
||
|
|
if (!code || !state) {
|
||
|
|
return {
|
||
|
|
errorCode: 'MISSING_PARAMETERS',
|
||
|
|
errorMessage: 'Code and state are required',
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await externalAuthService.handleOAuthCallback(
|
||
|
|
{ code, state },
|
||
|
|
{},
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!result.success) {
|
||
|
|
return {
|
||
|
|
errorCode: result.errorCode,
|
||
|
|
errorMessage: result.errorMessage,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const user = result.user!;
|
||
|
|
const expiresAt = Date.now() + 15 * 60 * 1000;
|
||
|
|
|
||
|
|
return {
|
||
|
|
identity: {
|
||
|
|
jwt: result.accessToken!,
|
||
|
|
refreshJwt: result.refreshToken!,
|
||
|
|
userId: user.id,
|
||
|
|
email: user.email,
|
||
|
|
username: user.username,
|
||
|
|
displayName: user.displayName,
|
||
|
|
isSystemAdmin: user.isSystemAdmin,
|
||
|
|
expiresAt,
|
||
|
|
sessionId: result.sessionId!,
|
||
|
|
},
|
||
|
|
user: {
|
||
|
|
id: user.id,
|
||
|
|
email: user.email,
|
||
|
|
username: user.username,
|
||
|
|
displayName: user.displayName,
|
||
|
|
avatarUrl: user.avatarUrl,
|
||
|
|
isSystemAdmin: user.isSystemAdmin,
|
||
|
|
isActive: user.isActive,
|
||
|
|
createdAt: user.createdAt instanceof Date ? user.createdAt.toISOString() : String(user.createdAt),
|
||
|
|
lastLoginAt: user.lastLoginAt instanceof Date ? user.lastLoginAt.toISOString() : user.lastLoginAt ? String(user.lastLoginAt) : undefined,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
} catch (error) {
|
||
|
|
if (error instanceof plugins.typedrequest.TypedResponseError) throw error;
|
||
|
|
throw new plugins.typedrequest.TypedResponseError('OAuth callback failed');
|
||
|
|
}
|
||
|
|
},
|
||
|
|
),
|
||
|
|
);
|
||
|
|
|
||
|
|
// LDAP Login
|
||
|
|
this.typedrouter.addTypedHandler(
|
||
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_LdapLogin>(
|
||
|
|
'ldapLogin',
|
||
|
|
async (dataArg) => {
|
||
|
|
try {
|
||
|
|
const { providerId, username, password } = dataArg;
|
||
|
|
|
||
|
|
if (!username || !password) {
|
||
|
|
throw new plugins.typedrequest.TypedResponseError(
|
||
|
|
'Username and password are required',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await externalAuthService.authenticateLdap(
|
||
|
|
providerId,
|
||
|
|
username,
|
||
|
|
password,
|
||
|
|
{},
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!result.success) {
|
||
|
|
return {
|
||
|
|
errorCode: result.errorCode,
|
||
|
|
errorMessage: result.errorMessage,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const user = result.user!;
|
||
|
|
const expiresAt = Date.now() + 15 * 60 * 1000;
|
||
|
|
|
||
|
|
return {
|
||
|
|
identity: {
|
||
|
|
jwt: result.accessToken!,
|
||
|
|
refreshJwt: result.refreshToken!,
|
||
|
|
userId: user.id,
|
||
|
|
email: user.email,
|
||
|
|
username: user.username,
|
||
|
|
displayName: user.displayName,
|
||
|
|
isSystemAdmin: user.isSystemAdmin,
|
||
|
|
expiresAt,
|
||
|
|
sessionId: result.sessionId!,
|
||
|
|
},
|
||
|
|
user: {
|
||
|
|
id: user.id,
|
||
|
|
email: user.email,
|
||
|
|
username: user.username,
|
||
|
|
displayName: user.displayName,
|
||
|
|
avatarUrl: user.avatarUrl,
|
||
|
|
isSystemAdmin: user.isSystemAdmin,
|
||
|
|
isActive: user.isActive,
|
||
|
|
createdAt: user.createdAt instanceof Date ? user.createdAt.toISOString() : String(user.createdAt),
|
||
|
|
lastLoginAt: user.lastLoginAt instanceof Date ? user.lastLoginAt.toISOString() : user.lastLoginAt ? String(user.lastLoginAt) : undefined,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
} catch (error) {
|
||
|
|
if (error instanceof plugins.typedrequest.TypedResponseError) throw error;
|
||
|
|
throw new plugins.typedrequest.TypedResponseError('LDAP login failed');
|
||
|
|
}
|
||
|
|
},
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|