[INIT] Initial Project Structure
Some checks failed
Deploy Edge / deploy-edge (push) Failing after 2s
S3 Repo Backup / s3-repo-backup (push) Failing after 2s

This commit is contained in:
Dunemask 2024-08-24 12:41:04 -06:00
commit 0fc5f05b6a
105 changed files with 10448 additions and 0 deletions

View file

@ -0,0 +1,60 @@
import config from "@lib/config";
import TableService from "../TableService";
import { CKeyPairContract } from "@lib/contracts/keypair.contracts";
import { KeyPairErrors, ProjectErrors } from "@lib/vix/ClientErrors";
import { encrypt, generateKeypair } from "@lib/svc/crypt.service";
import { KeyPair, KeyPairType } from "@prisma/client";
declare type Custom = "Custom"; // Make sure this matches KeyPairType.Custom;
export default class KeyPairTableService extends TableService {
protected table = "KeyPair";
async byId(keypairId: string) {
const keypair = this.pg.keyPair.findUnique({ where: { id: keypairId } });
if (!keypair) throw KeyPairErrors.NotFoundKeypair;
}
async byUsage(projectIdentity: string, usage: Custom): Promise<KeyPair[]>;
async byUsage(projectIdentity: string, usage: Exclude<KeyPairType, Custom>): Promise<KeyPair | null>;
async byUsage(projectIdentity: string, usage: KeyPairType): Promise<KeyPair[] | KeyPair | null> {
const projectOr = { OR: [{ id: projectIdentity }, { slug: projectIdentity }] };
const projectInclude = { keyPairs: { where: { usage: KeyPairType.UserToken } } };
const project = await this.pg.project.findFirst({ where: projectOr, include: projectInclude });
if (!project) throw ProjectErrors.BadRequestProjectIncomplete;
const keypairs = project.keyPairs;
if (usage !== KeyPairType.Custom && keypairs.length > 1)
throw new Error(`Multiple keypairs found for project ${projectIdentity} and usage ${usage}`);
if (usage !== KeyPairType.Custom && keypairs.length === 0) return null;
if (usage !== KeyPairType.Custom) return keypairs[0];
return keypairs;
}
async $upsertDefaultKeyPairs() {
const projectSlug = config.Server.projectSlug;
const cairoProject = await this.pg.project.findUnique({ where: { slug: projectSlug } });
if (!cairoProject) throw new Error("Cairo Project Not Found!");
const projectId = cairoProject.id;
await this.upsertProjecttDefaultKeyPairs(projectId);
}
async upsertProjecttDefaultKeyPairs(projectId: string) {
const storeKeypair = this.create.bind(this);
const keyTypes = Object.values(KeyPairType).filter((kp) => kp !== KeyPairType.Custom);
await Promise.all(
keyTypes.map(async (kp) => {
const existingKp = await this.byUsage(projectId, kp);
if (!!existingKp) return;
const { publicKey, privateKey } = await generateKeypair();
const [encryptedPrivateKey, encryptedPublicKey] = await Promise.all([
encrypt(privateKey, config.SigningOptions.Keys.KeyPair),
encrypt(publicKey, config.SigningOptions.Keys.KeyPair),
]);
return storeKeypair({ encryptedPrivateKey, encryptedPublicKey, projectId, usage: kp });
}),
);
}
async create(keypair: CKeyPairContract["Create"]) {
return this.pg.keyPair.create({ data: keypair });
}
}

View file

@ -0,0 +1,34 @@
import config from "@lib/config";
import TableService from "../TableService";
import { CProjectContract } from "@lib/types/ContractTypes";
import { ProjectErrors } from "@lib/vix/ClientErrors";
import { VERB } from "@dunemask/vix/logging";
export default class ProjectTableService extends TableService {
protected table = "Project";
async byId(projectId: string) {
return this.pg.project.findUnique({ where: { id: projectId } });
}
async bySlug(slug: string) {
return this.pg.project.findUnique({ where: { slug } });
}
async $upsertDefaultProject() {
const { projectSlug: slug, projectName: name } = config.Server;
const createOptions = { slug, name, parentProject: slug };
const existingProject = await this.pg.project.findUnique({ where: { slug } });
if (!!existingProject) return VERB("PROJECT", "Default project already exists!");
VERB("PROJECT", "Default project not found! Creating now!");
const proj = await this.pg.project.upsert({ where: { slug }, create: createOptions, update: createOptions });
await this.pg.project.update({ where: { id: proj.id }, data: { parentProject: proj.id } }); // Use ProjectID instead of slug
}
async create(project: CProjectContract["Create"] & { parentProject: string }) {
const existingProject = await this.pg.project.findMany({ where: { id: project.slug } });
if (existingProject.length > 1) throw ProjectErrors.BadRequestSlugInvalid;
return this.pg.project.create({ data: project }).catch(() => {
throw ProjectErrors.ConflictNonUnique;
});
}
}

View file

@ -0,0 +1,37 @@
import TableService from "../TableService";
import { AuthorityType } from "@prisma/client";
import { Policy, PolicyDefault } from "@lib/Policies";
import config from "@lib/config";
import { CRolePolicyContract } from "@lib/contracts/role-policy.contracts";
export default class RolePolicyTableService extends TableService {
protected table = "RolePolicy";
async byId(id: string) {
return this.pg.rolePolicy.findUnique({ where: { id } });
}
async $upsertDefaultAuthorities() {
const projectSlug = config.Server.projectSlug;
const cairoProject = await this.pg.project.findUnique({ where: { slug: projectSlug } });
if (!cairoProject) throw new Error("Cairo Project Not Found!");
const project = cairoProject.id;
const $chk = ({ id, name, policies }: PolicyDefault) => this.$upsertDefaultsAuthority(project, name, id, policies);
await Promise.all(Object.values(config.RolePolicy).map($chk));
}
private async $upsertDefaultsAuthority(projectId: string, name: string, id: string, userPolicies: Policy[]) {
const rootAuthority = config.RolePolicy.Root.id;
const authorityType = id === rootAuthority ? AuthorityType.Root : AuthorityType.RolePolicy;
const authority = id === rootAuthority ? name : rootAuthority; // Set Root Authority to root if root
const policies = Policy.asStrings(userPolicies);
return this.pg.rolePolicy.upsert({
where: { id },
create: { projectId, id, name, policies, authority, authorityType },
update: { projectId, name, policies, authority, authorityType },
});
}
async create(rp: CRolePolicyContract["Create"]) {
return this.pg.rolePolicy.create({ data: rp });
}
}

View file

@ -0,0 +1,63 @@
import config from "@lib/config";
import TableService from "../TableService";
import { CUserContract } from "@lib/types/ContractTypes";
import { hashText } from "@lib/modules/auth/auth.service";
import { KeyPairType } from "@prisma/client";
import { UserErrors } from "@lib/vix/ClientErrors";
// prettier-ignore
const generateBase64Password = (length: number = 32): string => Array.from(crypto.getRandomValues(new Uint8Array(length)), byte => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charAt(byte % 64)).join('');
export default class UsersTableService extends TableService {
protected table = "User";
async byId(userId: string) {
return this.pg.user.findUnique({ where: { id: userId }, include: { rolePolicy: true, project: true } });
}
async byUsername(username: string, projectId: string) {
return this.pg.user.findUnique({ where: { projectId_username: { projectId, username } } });
}
async byEmail(email: string, projectId: string) {
return this.pg.user.findUnique({ where: { projectId_email: { projectId, email } } });
}
async $upsertDefaultRootUser() {
const project = await this.pg.project.findUnique({ where: { slug: config.Server.projectSlug } });
if (!project) throw new Error("Cairo Project Not Found!");
const rolePolicyId = config.RolePolicy.Root.id;
return this.$upsertRootUser(project.id, rolePolicyId);
}
async $upsertRootUser(projectId: string, rolePolicyId: string) {
const root = await this.pg.user.findUnique({ where: { projectId_username: { username: "root", projectId } } });
if (!!root) return;
const password = config.Server.rootPassword ?? generateBase64Password();
const hash = await hashText(password);
const user = await this.pg.user.create({ data: { projectId, username: "root", email: "root", hash, rolePolicyId } });
return { ...user, password };
}
async create(options: CUserContract["Create"]) {
const { hash, projectId, rolePolicyId } = options;
const username = options.username?.toLowerCase();
const email = options.email?.toLowerCase() ?? undefined;
const [existingUsername, existingEmail] = await Promise.all([
this.byUsername(username, projectId),
!!email ? this.byEmail(email, projectId) : undefined,
]);
if (!existingUsername || !existingEmail) throw UserErrors.ConflictIdentityTaken;
const userData = { projectId, username, email, hash, rolePolicyId };
return this.pg.user.create({ data: userData, include: { rolePolicy: true } });
}
async byIdentity(projectIdentity: string, identity: string) {
const username = identity.toLowerCase();
const email = identity.toLowerCase();
const OrUser = { OR: [{ username }, { email }] };
const OrProject = { project: { OR: [{ id: projectIdentity }, { slug: projectIdentity }] } };
const projectInclude = { include: { keyPairs: { where: { usage: KeyPairType.UserToken } } } };
const AND = [OrUser, OrProject];
return this.pg.user.findFirst({ where: { AND }, include: { rolePolicy: true, project: projectInclude } });
}
}