feat: add functional authentication
This commit is contained in:
19
api/stores/read-store/.tasks/bootstrap.ts
Normal file
19
api/stores/read-store/.tasks/bootstrap.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { idIndex } from "~libraries/database/id.ts";
|
||||
import { register } from "~libraries/database/registrar.ts";
|
||||
|
||||
import { db } from "../database.ts";
|
||||
|
||||
await register(db.db, [
|
||||
{
|
||||
name: "accounts",
|
||||
indexes: [
|
||||
idIndex,
|
||||
[{ "strategies.type": 1, "strategies.alias": 1 }, { name: "strategy.password" }],
|
||||
[{ "strategies.type": 1, "strategies.value": 1 }, { name: "strategy.email" }],
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "roles",
|
||||
indexes: [idIndex, [{ name: 1 }, { name: "role.name" }]],
|
||||
},
|
||||
]);
|
||||
14
api/stores/read-store/database.ts
Normal file
14
api/stores/read-store/database.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RoleDocument } from "@spec/schemas/access/role.ts";
|
||||
import type { AccountDocument } from "@spec/schemas/account/account.ts";
|
||||
|
||||
import { config } from "~config";
|
||||
import { getDatabaseAccessor } from "~libraries/database/accessor.ts";
|
||||
|
||||
export const db = getDatabaseAccessor<{
|
||||
accounts: AccountDocument;
|
||||
roles: RoleDocument;
|
||||
}>(`${config.name}:read-store`);
|
||||
|
||||
export function takeOne<TDocument>(documents: TDocument[]): TDocument | undefined {
|
||||
return documents[0];
|
||||
}
|
||||
65
api/stores/read-store/methods.ts
Normal file
65
api/stores/read-store/methods.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { type Account, fromAccountDocument } from "@spec/schemas/account/account.ts";
|
||||
import { PasswordStrategy } from "@spec/schemas/auth/strategies.ts";
|
||||
|
||||
import { db, takeOne } from "./database.ts";
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Accounts
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieve a single account by its primary identifier.
|
||||
*
|
||||
* @param id - Account identifier.
|
||||
*/
|
||||
export async function getAccountById(id: string): Promise<Account | undefined> {
|
||||
return db
|
||||
.collection("accounts")
|
||||
.aggregate([
|
||||
{
|
||||
$match: { id },
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: "roles",
|
||||
localField: "roles",
|
||||
foreignField: "id",
|
||||
as: "roles",
|
||||
},
|
||||
},
|
||||
])
|
||||
.toArray()
|
||||
.then(fromAccountDocument)
|
||||
.then(takeOne);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------------
|
||||
| Auth
|
||||
|--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get strategy details for the given password strategy alias.
|
||||
*
|
||||
* @param alias - Alias to get strategy for.
|
||||
*/
|
||||
export async function getPasswordStrategyByAlias(
|
||||
alias: string,
|
||||
): Promise<({ accountId: string } & PasswordStrategy) | undefined> {
|
||||
const account = await db.collection("accounts").findOne({
|
||||
strategies: {
|
||||
$elemMatch: { type: "password", alias },
|
||||
},
|
||||
});
|
||||
if (account === null) {
|
||||
return undefined;
|
||||
}
|
||||
const strategy = account.strategies.find((strategy) => strategy.type === "password" && strategy.alias === alias);
|
||||
if (strategy === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return { accountId: account.id, ...strategy } as { accountId: string } & PasswordStrategy;
|
||||
}
|
||||
Reference in New Issue
Block a user