mirror of https://github.com/wg-easy/wg-easy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
4.2 KiB
166 lines
4.2 KiB
import type { H3Event } from 'h3';
|
|
import { discovery } from 'openid-client';
|
|
|
|
type OAuthConfig = {
|
|
friendlyName: string;
|
|
server: string;
|
|
scope: string;
|
|
clientId: string | undefined;
|
|
clientSecret: string | undefined;
|
|
params: Record<string, string>;
|
|
isOIDC?: false;
|
|
userInfoFlow?: 'github';
|
|
};
|
|
|
|
const GoogleConfig: OAuthConfig = {
|
|
friendlyName: 'Google',
|
|
server: 'https://accounts.google.com',
|
|
scope: 'openid email profile',
|
|
clientId: process.env.OAUTH_GOOGLE_CLIENT_ID,
|
|
clientSecret: process.env.OAUTH_GOOGLE_CLIENT_SECRET,
|
|
params: {
|
|
access_type: 'online',
|
|
prompt: 'select_account',
|
|
},
|
|
};
|
|
const GithubConfig: OAuthConfig = {
|
|
friendlyName: 'GitHub',
|
|
server: 'https://github.com/login/oauth',
|
|
scope: 'read:user user:email',
|
|
clientId: process.env.OAUTH_GITHUB_CLIENT_ID,
|
|
clientSecret: process.env.OAUTH_GITHUB_CLIENT_SECRET,
|
|
params: {
|
|
allow_signup: 'false',
|
|
prompt: 'select_account',
|
|
},
|
|
isOIDC: false,
|
|
userInfoFlow: 'github',
|
|
};
|
|
const OidcConfig: OAuthConfig = {
|
|
friendlyName: process.env.OAUTH_OIDC_NAME ?? 'OIDC',
|
|
server: process.env.OAUTH_OIDC_SERVER ?? '',
|
|
scope: 'openid email profile',
|
|
clientId: process.env.OAUTH_OIDC_CLIENT_ID,
|
|
clientSecret: process.env.OAUTH_OIDC_CLIENT_SECRET,
|
|
params: {},
|
|
};
|
|
|
|
export const OAUTH_PROVIDERS = {
|
|
google: GoogleConfig,
|
|
github: GithubConfig,
|
|
oidc: OidcConfig,
|
|
};
|
|
|
|
export type OAUTH_PROVIDER = keyof typeof OAUTH_PROVIDERS;
|
|
|
|
export function isValidOauthProvider(
|
|
provider: string
|
|
): provider is OAUTH_PROVIDER {
|
|
if (provider in OAUTH_PROVIDERS) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export function isConfiguredOauthProvider(
|
|
oauthProvider: (typeof OAUTH_PROVIDERS)[OAUTH_PROVIDER]
|
|
): oauthProvider is (typeof OAUTH_PROVIDERS)[OAUTH_PROVIDER] & {
|
|
clientId: string;
|
|
clientSecret: string;
|
|
} {
|
|
if (!oauthProvider.clientId || !oauthProvider.clientSecret) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function isEnabledProvider(provider: OAUTH_PROVIDER) {
|
|
return WG_ENV.OAUTH_PROVIDERS?.includes(provider);
|
|
}
|
|
|
|
// TODO: simplify logic between WG_ENV.OAUTH_PROVIDERS and buildOauthConfig
|
|
export async function buildOauthConfig(event: H3Event) {
|
|
const provider = getRouterParam(event, 'provider');
|
|
if (!provider || !isValidOauthProvider(provider)) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Invalid provider',
|
|
});
|
|
}
|
|
|
|
if (!isEnabledProvider(provider)) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Disabled provider',
|
|
});
|
|
}
|
|
|
|
const oauthProvider = OAUTH_PROVIDERS[provider];
|
|
|
|
if (!isConfiguredOauthProvider(oauthProvider)) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: 'Provider is not configured',
|
|
});
|
|
}
|
|
|
|
const config = await discovery(
|
|
new URL(oauthProvider.server),
|
|
oauthProvider.clientId,
|
|
{
|
|
client_secret: oauthProvider.clientSecret,
|
|
}
|
|
);
|
|
|
|
return { config, providerConfig: oauthProvider, provider };
|
|
}
|
|
|
|
export async function githubUserInfoFlow(accessToken: string) {
|
|
const OAUTH_GITHUB_FLOW = {
|
|
userinfo_endpoint: 'https://api.github.com/user',
|
|
email_endpoint: 'https://api.github.com/user/emails',
|
|
};
|
|
type OAUTH_GITHUB_USERINFO = {
|
|
id: number;
|
|
login: string;
|
|
avatar_url: string;
|
|
email: string | null;
|
|
name: string | null;
|
|
};
|
|
type OAUTH_GITHUB_EMAIL = {
|
|
email: string;
|
|
primary: boolean;
|
|
verified: boolean;
|
|
visibility: string | null;
|
|
}[];
|
|
|
|
const response = await $fetch<OAUTH_GITHUB_USERINFO>(
|
|
OAUTH_GITHUB_FLOW.userinfo_endpoint,
|
|
{
|
|
headers: {
|
|
'User-Agent': 'wg-easy',
|
|
Authorization: `Bearer ${accessToken}`,
|
|
},
|
|
}
|
|
);
|
|
if (!response.email) {
|
|
const emailResponse = await $fetch<OAUTH_GITHUB_EMAIL>(
|
|
OAUTH_GITHUB_FLOW.email_endpoint,
|
|
{
|
|
headers: {
|
|
'User-Agent': 'wg-easy',
|
|
Authorization: `Bearer ${accessToken}`,
|
|
},
|
|
}
|
|
);
|
|
const primaryEmail = emailResponse.find((v) => v.primary && v.verified);
|
|
response.email = primaryEmail?.email || null;
|
|
}
|
|
return {
|
|
sub: response.id.toString(),
|
|
email: response.email,
|
|
email_verified: true,
|
|
preferred_username: response.login,
|
|
name: response.name || response.login,
|
|
};
|
|
}
|
|
|