add prettier

This commit is contained in:
2023-08-06 09:21:17 +03:00
parent cc453e2337
commit feb5e5b4ca
25 changed files with 524 additions and 591 deletions

View File

@@ -1,186 +1,142 @@
import type {
NullableId,
Params,
ServiceInterface,
} from "@feathersjs/feathers";
import type { NullableId, Params, ServiceInterface } from '@feathersjs/feathers';
import type { Application } from "../../declarations";
import wildDuckClient from "../../clients/wildduck.client";
import { faker, th } from "@faker-js/faker";
import { BadRequest } from "@feathersjs/errors";
import config from "config";
import type { Application } from '../../declarations';
import wildDuckClient from '../../clients/wildduck.client';
import { faker, th } from '@faker-js/faker';
import { BadRequest } from '@feathersjs/errors';
import config from 'config';
interface WildDuckAddress {
success: boolean;
id: string;
address: string;
main: boolean;
user: string;
tags: string[];
created: string;
success: boolean;
id: string;
address: string;
main: boolean;
user: string;
tags: string[];
created: string;
}
interface GetWildDuckAddressInfoResponse {
success: boolean;
results: WildDuckAddress[];
success: boolean;
results: WildDuckAddress[];
}
interface AliasApiResponse {
id: string | null;
address: string;
tags: string[];
created: string;
id: string | null;
address: string;
tags: string[];
created: string;
}
interface CreateWildDuckAddressResponse {
success: boolean;
id: string;
success: boolean;
id: string;
}
type AliasesData = any;
type AliasesPatch = any;
type AliasesQuery = any;
export type {
WildDuckAddress as Aliases,
AliasesData,
AliasesPatch,
AliasesQuery,
};
export type { WildDuckAddress as Aliases, AliasesData, AliasesPatch, AliasesQuery };
export interface AliasesServiceOptions {
app: Application;
app: Application;
}
export interface AliasesParams extends Params<AliasesQuery> {
session?: any;
session?: any;
}
export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
implements
ServiceInterface<
AliasApiResponse,
AliasesData,
ServiceParams,
AliasesPatch
>
implements ServiceInterface<AliasApiResponse, AliasesData, ServiceParams, AliasesPatch>
{
constructor(public options: AliasesServiceOptions) {}
constructor(public options: AliasesServiceOptions) {}
async find(params: ServiceParams): Promise<AliasApiResponse[]> {
const userId = await this.getUserIdByEmailAddress(params);
async find(params: ServiceParams): Promise<AliasApiResponse[]> {
const userId = await this.getUserIdByEmailAddress(params);
return this.getUserAddresses(userId);
}
async create(
data: AliasesData,
params: ServiceParams,
): Promise<AliasApiResponse>;
async create(
data: AliasesData,
params: ServiceParams,
): Promise<AliasApiResponse | AliasApiResponse[]> {
const userId = await this.getUserIdByEmailAddress(params);
const randomString = faker.git.commitSha({ length: 4 });
// Replace all non-alphanumeric characters with nothing and spaces with dashes
const alias =
`${faker.color.human()}-${faker.animal.snake()}-${randomString}`
.replace(/\s+/g, "-")
.replace(/[^a-zA-Z0-9-]/g, "")
.toLowerCase();
const emailDomain = config.get("wildDuck.domain");
const createResult =
await wildDuckClient.post<CreateWildDuckAddressResponse>(
`/users/${userId}/addresses`,
{
address: `${alias}@${emailDomain}`,
},
);
if (!createResult.data.success) {
throw new BadRequest("Failed to create alias");
return this.getUserAddresses(userId);
}
return this.getUserAddresses(userId);
}
async create(data: AliasesData, params: ServiceParams): Promise<AliasApiResponse>;
async create(data: AliasesData, params: ServiceParams): Promise<AliasApiResponse | AliasApiResponse[]> {
const userId = await this.getUserIdByEmailAddress(params);
private async getUserIdByEmailAddress(
params: ServiceParams,
): Promise<string> {
const emails = params.session?.user?.emails;
const randomString = faker.git.commitSha({ length: 4 });
const preferredDomain = config.get("wildDuck.preferredDomain");
// Replace all non-alphanumeric characters with nothing and spaces with dashes
const alias = `${faker.color.human()}-${faker.animal.snake()}-${randomString}`
.replace(/\s+/g, '-')
.replace(/[^a-zA-Z0-9-]/g, '')
.toLowerCase();
if (!emails.length || !preferredDomain) {
throw new BadRequest("Unable to find user");
const emailDomain = config.get('wildDuck.domain');
const createResult = await wildDuckClient.post<CreateWildDuckAddressResponse>(`/users/${userId}/addresses`, {
address: `${alias}@${emailDomain}`,
});
if (!createResult.data.success) {
throw new BadRequest('Failed to create alias');
}
return this.getUserAddresses(userId);
}
const addressInfoResponse = await Promise.any(
emails
.filter((email: string) =>
email.endsWith(config.get("wildDuck.preferredDomain")),
)
.map((email: string) =>
wildDuckClient.get<WildDuckAddress>(`addresses/resolve/${email}`),
),
);
private async getUserIdByEmailAddress(params: ServiceParams): Promise<string> {
const emails = params.session?.user?.emails;
return addressInfoResponse.data.user;
}
const preferredDomain = config.get('wildDuck.preferredDomain');
private async getUserAddresses(userId: string): Promise<AliasApiResponse[]> {
const { data: userAddressesResponse } =
await wildDuckClient.get<GetWildDuckAddressInfoResponse>(
`/users/${userId}/addresses`,
);
if (!emails.length || !preferredDomain) {
throw new BadRequest('Unable to find user');
}
return userAddressesResponse.results.map(this.sanitizeAliasResponse);
}
const addressInfoResponse = await Promise.any(
emails
.filter((email: string) => email.endsWith(config.get('wildDuck.preferredDomain')))
.map((email: string) => wildDuckClient.get<WildDuckAddress>(`addresses/resolve/${email}`))
);
async remove(
id: NullableId,
params: ServiceParams,
): Promise<AliasApiResponse[]> {
const { data: addressInfoResponse } =
await wildDuckClient.get<WildDuckAddress>(`addresses/resolve/${id}`);
const allowedDomain: string = config.get("wildDuck.domain");
// If address does not match the allowed domain, throw an error
if (
!allowedDomain ||
!addressInfoResponse.address.endsWith(allowedDomain)
) {
throw new BadRequest("Unable to delete address");
return addressInfoResponse.data.user;
}
const userId = await this.getUserIdByEmailAddress(params);
await wildDuckClient.delete<WildDuckAddress>(
`users/${userId}/addresses/${id}`,
);
private async getUserAddresses(userId: string): Promise<AliasApiResponse[]> {
const { data: userAddressesResponse } = await wildDuckClient.get<GetWildDuckAddressInfoResponse>(
`/users/${userId}/addresses`
);
return this.getUserAddresses(userId);
}
return userAddressesResponse.results.map(this.sanitizeAliasResponse);
}
sanitizeAliasResponse(alias: WildDuckAddress): AliasApiResponse {
// Hide the id if the alias is not removable
const isRemovable =
alias.main ||
!alias.address.endsWith(config.get("wildDuck.preferredDomain"));
async remove(id: NullableId, params: ServiceParams): Promise<AliasApiResponse[]> {
const { data: addressInfoResponse } = await wildDuckClient.get<WildDuckAddress>(`addresses/resolve/${id}`);
const allowedDomain: string = config.get('wildDuck.domain');
return {
id: isRemovable ? null : alias.id,
address: alias.address,
tags: alias.tags,
created: alias.created,
};
}
// If address does not match the allowed domain, throw an error
if (!allowedDomain || !addressInfoResponse.address.endsWith(allowedDomain)) {
throw new BadRequest('Unable to delete address');
}
const userId = await this.getUserIdByEmailAddress(params);
await wildDuckClient.delete<WildDuckAddress>(`users/${userId}/addresses/${id}`);
return this.getUserAddresses(userId);
}
sanitizeAliasResponse(alias: WildDuckAddress): AliasApiResponse {
// Hide the id if the alias is not removable
const isRemovable = alias.main || !alias.address.endsWith(config.get('wildDuck.preferredDomain'));
return {
id: isRemovable ? null : alias.id,
address: alias.address,
tags: alias.tags,
created: alias.created,
};
}
}
export const getOptions = (app: Application) => {
return { app };
return { app };
};

View File

@@ -1,39 +1,39 @@
import type { Application } from "../../declarations";
import { validateAuth } from "../../hooks/validate-auth";
import { AliasesService, getOptions } from "./aliases.class";
import type { Application } from '../../declarations';
import { validateAuth } from '../../hooks/validate-auth';
import { AliasesService, getOptions } from './aliases.class';
export const aliasesPath = "aliases";
export const aliasesMethods = ["find", "create", "remove"] as const;
export const aliasesPath = 'aliases';
export const aliasesMethods = ['find', 'create', 'remove'] as const;
export * from "./aliases.class";
export * from './aliases.class';
export const aliases = (app: Application) => {
app.use(aliasesPath, new AliasesService(getOptions(app)), {
methods: aliasesMethods,
events: [],
});
app.use(aliasesPath, new AliasesService(getOptions(app)), {
methods: aliasesMethods,
events: [],
});
app.service(aliasesPath).hooks({
around: {
all: [],
},
before: {
all: [validateAuth],
find: [],
create: [],
},
after: {
all: [],
},
error: {
all: [],
},
});
app.service(aliasesPath).hooks({
around: {
all: [],
},
before: {
all: [validateAuth],
find: [],
create: [],
},
after: {
all: [],
},
error: {
all: [],
},
});
};
// Add this service to the service type index
declare module "../../declarations" {
interface ServiceTypes {
[aliasesPath]: AliasesService;
}
declare module '../../declarations' {
interface ServiceTypes {
[aliasesPath]: AliasesService;
}
}

View File

@@ -1,9 +1,9 @@
import type { Params, ServiceInterface } from "@feathersjs/feathers";
import type { Params, ServiceInterface } from '@feathersjs/feathers';
import type { Application } from "../../declarations";
import type { Application } from '../../declarations';
import { Issuer, generators } from "openid-client";
import config from "config";
import { Issuer, generators } from 'openid-client';
import config from 'config';
type AuthOidcResponse = string;
type AuthOidcQuery = any;
@@ -11,43 +11,42 @@ type AuthOidcQuery = any;
export type { AuthOidcResponse as AuthOidc, AuthOidcQuery };
export interface AuthOidcServiceOptions {
app: Application;
app: Application;
}
export interface AuthOidcParams extends Params<AuthOidcQuery> {
session?: any;
session?: any;
}
export class AuthOidcService<
ServiceParams extends AuthOidcParams = AuthOidcParams,
> implements ServiceInterface<AuthOidcResponse, ServiceParams>
export class AuthOidcService<ServiceParams extends AuthOidcParams = AuthOidcParams>
implements ServiceInterface<AuthOidcResponse, ServiceParams>
{
constructor(public options: AuthOidcServiceOptions) {}
constructor(public options: AuthOidcServiceOptions) {}
async find(params: ServiceParams): Promise<AuthOidcResponse> {
const issuer = await Issuer.discover(config.get("oidc.gatewayUri"));
const client = new issuer.Client({
client_id: config.get("oidc.clientId"),
client_secret: config.get("oidc.clientSecret"),
redirect_uris: [config.get("oidc.redirectUris")],
response_types: ["code"],
});
const codeVerifier = generators.codeVerifier();
const codeChallenge = generators.codeChallenge(codeVerifier);
async find(params: ServiceParams): Promise<AuthOidcResponse> {
const issuer = await Issuer.discover(config.get('oidc.gatewayUri'));
const client = new issuer.Client({
client_id: config.get('oidc.clientId'),
client_secret: config.get('oidc.clientSecret'),
redirect_uris: [config.get('oidc.redirectUris')],
response_types: ['code'],
});
const codeVerifier = generators.codeVerifier();
const codeChallenge = generators.codeChallenge(codeVerifier);
const url = client.authorizationUrl({
redirect_uri: config.get("clientUrl") + "/auth-oidc/callback",
scope: "openid profile offline_access",
response_type: "code",
code_challenge: codeChallenge,
code_challenge_method: "S256",
});
const url = client.authorizationUrl({
redirect_uri: config.get('clientUrl') + '/auth-oidc/callback',
scope: 'openid profile offline_access',
response_type: 'code',
code_challenge: codeChallenge,
code_challenge_method: 'S256',
});
params.session.codeVerifier = codeVerifier;
return url;
}
params.session.codeVerifier = codeVerifier;
return url;
}
}
export const getOptions = (app: Application) => {
return { app };
return { app };
};

View File

@@ -1,45 +1,45 @@
import type { Application } from "../../declarations";
import { AuthOidcService, getOptions } from "./auth-oidc.class";
import type { Application } from '../../declarations';
import { AuthOidcService, getOptions } from './auth-oidc.class';
export const authOidcPath = "auth-oidc";
export const authOidcMethods = ["find"] as const;
export const authOidcPath = 'auth-oidc';
export const authOidcMethods = ['find'] as const;
export * from "./auth-oidc.class";
export * from './auth-oidc.class';
export const authOidc = (app: Application) => {
// TODO: fix this to use the correct type
// @ts-ignore
app.use(
authOidcPath,
new AuthOidcService(getOptions(app)),
{
methods: authOidcMethods,
events: [],
},
(req: any, res: any) => {
return res.redirect(res.data);
},
);
// TODO: fix this to use the correct type
// @ts-ignore
app.use(
authOidcPath,
new AuthOidcService(getOptions(app)),
{
methods: authOidcMethods,
events: [],
},
(req: any, res: any) => {
return res.redirect(res.data);
}
);
app.service(authOidcPath).hooks({
around: {
all: [],
},
before: {
all: [],
find: [],
},
after: {
all: [],
},
error: {
all: [],
},
});
app.service(authOidcPath).hooks({
around: {
all: [],
},
before: {
all: [],
find: [],
},
after: {
all: [],
},
error: {
all: [],
},
});
};
declare module "../../declarations" {
interface ServiceTypes {
[authOidcPath]: AuthOidcService;
}
declare module '../../declarations' {
interface ServiceTypes {
[authOidcPath]: AuthOidcService;
}
}

View File

@@ -1,68 +1,56 @@
import type { Params, ServiceInterface } from "@feathersjs/feathers";
import type { Application } from "../../../declarations";
import { Issuer } from "openid-client";
import type { Params, ServiceInterface } from '@feathersjs/feathers';
import type { Application } from '../../../declarations';
import { Issuer } from 'openid-client';
import config from "config";
import config from 'config';
type AuthOidcCallback = string;
type AuthOidcCallbackData = any;
type AuthOidcCallbackPatch = any;
type AuthOidcCallbackQuery = any;
export type {
AuthOidcCallback,
AuthOidcCallbackData,
AuthOidcCallbackPatch,
AuthOidcCallbackQuery,
};
export type { AuthOidcCallback, AuthOidcCallbackData, AuthOidcCallbackPatch, AuthOidcCallbackQuery };
export interface AuthOidcCallbackServiceOptions {
app: Application;
app: Application;
}
export interface AuthOidcCallbackParams extends Params<AuthOidcCallbackQuery> {
session?: any;
query: {
iss: string;
code: string;
};
session?: any;
query: {
iss: string;
code: string;
};
}
export class AuthOidcCallbackService<
ServiceParams extends AuthOidcCallbackParams = AuthOidcCallbackParams,
> implements
ServiceInterface<
AuthOidcCallback,
AuthOidcCallbackData,
ServiceParams,
AuthOidcCallbackPatch
>
export class AuthOidcCallbackService<ServiceParams extends AuthOidcCallbackParams = AuthOidcCallbackParams>
implements ServiceInterface<AuthOidcCallback, AuthOidcCallbackData, ServiceParams, AuthOidcCallbackPatch>
{
constructor(public options: AuthOidcCallbackServiceOptions) {}
constructor(public options: AuthOidcCallbackServiceOptions) {}
async find(params: ServiceParams): Promise<AuthOidcCallback> {
const issuer = await Issuer.discover(config.get("oidc.gatewayUri"));
const client = new issuer.Client({
client_id: config.get("oidc.clientId"),
client_secret: config.get("oidc.clientSecret"),
redirect_uris: [config.get("oidc.redirectUris")],
response_types: ["code"],
});
async find(params: ServiceParams): Promise<AuthOidcCallback> {
const issuer = await Issuer.discover(config.get('oidc.gatewayUri'));
const client = new issuer.Client({
client_id: config.get('oidc.clientId'),
client_secret: config.get('oidc.clientSecret'),
redirect_uris: [config.get('oidc.redirectUris')],
response_types: ['code'],
});
const codeVerifier = params.session.codeVerifier;
const tokenSet = await client.callback(
config.get("clientUrl") + "/auth-oidc/callback",
{ code: params.query.code, iss: params.query.iss },
{ code_verifier: codeVerifier },
);
const userinfo = await client.userinfo(tokenSet.access_token as string);
const codeVerifier = params.session.codeVerifier;
const tokenSet = await client.callback(
config.get('clientUrl') + '/auth-oidc/callback',
{ code: params.query.code, iss: params.query.iss },
{ code_verifier: codeVerifier }
);
const userinfo = await client.userinfo(tokenSet.access_token as string);
params.session.user = userinfo;
params.session.user = userinfo;
return "/";
}
return '/';
}
}
export const getOptions = (app: Application) => {
return { app };
return { app };
};

View File

@@ -1,49 +1,46 @@
import { http } from "@feathersjs/transport-commons";
import type { Application } from "../../../declarations";
import {
AuthOidcCallbackService,
getOptions,
} from "./auth-oidc-callback.class";
import { http } from '@feathersjs/transport-commons';
import type { Application } from '../../../declarations';
import { AuthOidcCallbackService, getOptions } from './auth-oidc-callback.class';
export const authOidcCallbackPath = "auth-oidc/callback";
export const authOidcCallbackMethods = ["find"] as const;
export const authOidcCallbackPath = 'auth-oidc/callback';
export const authOidcCallbackMethods = ['find'] as const;
export * from "./auth-oidc-callback.class";
export * from './auth-oidc-callback.class';
export const authOidcCallback = (app: Application) => {
// TODO: fix this to use the correct type
// @ts-ignore
app.use(
authOidcCallbackPath,
new AuthOidcCallbackService(getOptions(app)),
{
methods: authOidcCallbackMethods,
events: [],
},
(req: any, res: any) => {
return res.redirect(res.data);
},
);
// TODO: fix this to use the correct type
// @ts-ignore
app.use(
authOidcCallbackPath,
new AuthOidcCallbackService(getOptions(app)),
{
methods: authOidcCallbackMethods,
events: [],
},
(req: any, res: any) => {
return res.redirect(res.data);
}
);
app.service(authOidcCallbackPath).hooks({
around: {
all: [],
},
before: {
all: [],
find: [],
},
after: {
all: [],
},
error: {
all: [],
},
});
app.service(authOidcCallbackPath).hooks({
around: {
all: [],
},
before: {
all: [],
find: [],
},
after: {
all: [],
},
error: {
all: [],
},
});
};
declare module "../../../declarations" {
interface ServiceTypes {
[authOidcCallbackPath]: AuthOidcCallbackService;
}
declare module '../../../declarations' {
interface ServiceTypes {
[authOidcCallbackPath]: AuthOidcCallbackService;
}
}

View File

@@ -1,10 +1,10 @@
import { authOidcCallback } from "./auth-oidc/callback/auth-oidc-callback";
import { authOidc } from "./auth-oidc/auth-oidc";
import { aliases } from "./aliases/aliases";
import type { Application } from "../declarations";
import { authOidcCallback } from './auth-oidc/callback/auth-oidc-callback';
import { authOidc } from './auth-oidc/auth-oidc';
import { aliases } from './aliases/aliases';
import type { Application } from '../declarations';
export const services = (app: Application) => {
app.configure(authOidcCallback);
app.configure(authOidc);
app.configure(aliases);
app.configure(authOidcCallback);
app.configure(authOidc);
app.configure(aliases);
};