138 lines
3.5 KiB
TypeScript
138 lines
3.5 KiB
TypeScript
import type {
|
|
NullableId,
|
|
Params,
|
|
ServiceInterface,
|
|
} from "@feathersjs/feathers";
|
|
|
|
import type { Application } from "../../declarations";
|
|
import wildDuckClient from "../../clients/wildduck.client";
|
|
import { faker } from "@faker-js/faker";
|
|
import { BadRequest } from "@feathersjs/errors";
|
|
import config from "config";
|
|
|
|
interface Alias {
|
|
success: boolean;
|
|
id: string;
|
|
address: string;
|
|
main: boolean;
|
|
user: string;
|
|
tags: string[];
|
|
created: string;
|
|
}
|
|
|
|
interface GetAddressInfoResponse {
|
|
success: boolean;
|
|
results: Alias[];
|
|
}
|
|
|
|
interface CreateAddressResponse {
|
|
success: boolean;
|
|
id: string;
|
|
}
|
|
|
|
type AliasesData = any;
|
|
type AliasesPatch = any;
|
|
type AliasesQuery = any;
|
|
|
|
export type { Alias as Aliases, AliasesData, AliasesPatch, AliasesQuery };
|
|
|
|
export interface AliasesServiceOptions {
|
|
app: Application;
|
|
}
|
|
|
|
export interface AliasesParams extends Params<AliasesQuery> {
|
|
session?: any;
|
|
}
|
|
|
|
export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
|
implements ServiceInterface<Alias, AliasesData, ServiceParams, AliasesPatch>
|
|
{
|
|
constructor(public options: AliasesServiceOptions) {}
|
|
|
|
async find(params: ServiceParams): Promise<Alias[]> {
|
|
const userId = await this.getUserIdByEmailAddress(params);
|
|
|
|
return this.getUserAddresses(userId);
|
|
}
|
|
|
|
async create(data: AliasesData, params: ServiceParams): Promise<Alias>;
|
|
async create(
|
|
data: AliasesData,
|
|
params: ServiceParams,
|
|
): Promise<Alias | Alias[]> {
|
|
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<CreateAddressResponse>(
|
|
`/users/${userId}/addresses`,
|
|
{
|
|
address: `${alias}@${emailDomain}`,
|
|
},
|
|
);
|
|
|
|
if (!createResult.data.success) {
|
|
throw new BadRequest("Failed to create alias");
|
|
}
|
|
|
|
return this.getUserAddresses(userId);
|
|
}
|
|
|
|
private async getUserIdByEmailAddress(
|
|
params: ServiceParams,
|
|
): Promise<string> {
|
|
const emails = params.session?.user?.emails;
|
|
|
|
const addressInfoResponse = await Promise.any(
|
|
emails.map((email: string) =>
|
|
wildDuckClient.get<Alias>(`addresses/resolve/${email}`),
|
|
),
|
|
);
|
|
|
|
return addressInfoResponse.data.user;
|
|
}
|
|
|
|
private async getUserAddresses(userId: string): Promise<Alias[]> {
|
|
const { data: userAddressesResponse } =
|
|
await wildDuckClient.get<GetAddressInfoResponse>(
|
|
`/users/${userId}/addresses`,
|
|
);
|
|
|
|
return userAddressesResponse.results;
|
|
}
|
|
|
|
async remove(id: NullableId, params: ServiceParams): Promise<Alias[]> {
|
|
const { data: addressInfoResponse } = await wildDuckClient.get<Alias>(
|
|
`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");
|
|
}
|
|
|
|
await wildDuckClient.delete<Alias>(`/addresses/${id}`);
|
|
|
|
const userId = await this.getUserIdByEmailAddress(params);
|
|
|
|
return this.getUserAddresses(userId);
|
|
}
|
|
}
|
|
|
|
export const getOptions = (app: Application) => {
|
|
return { app };
|
|
};
|