Compare commits

..

30 commits

Author SHA1 Message Date
bd56e44585
Merge pull request #60 from chris-kruining/renovate/actions-checkout-5.x 2025-08-12 10:37:39 +02:00
renovate[bot]
9cb1984c8f
Update actions/checkout action to v5 2025-08-11 13:38:03 +00:00
02a980eb79
Merge pull request #59 from chris-kruining/renovate/gittools-actions-4.x 2025-08-07 13:51:58 +02:00
renovate[bot]
a238acf0db
Update gittools/actions action to v4.1.0 2025-08-07 11:27:35 +00:00
Chris Kruining
2595c53f83
fix formatting? 2025-07-21 16:20:58 +02:00
Chris Kruining
155b82cbea
update az cli 2025-07-21 16:12:55 +02:00
Chris Kruining
12e3cf2f85
fix dockerfile 2025-07-21 15:41:42 +02:00
Chris Kruining
e59c210ef4
just remove the config file and fall back to gitversion defaults 2025-07-21 15:30:45 +02:00
Chris Kruining
1fec60d46e
remove old input 2025-07-21 15:29:20 +02:00
Chris Kruining
8401ac9593
remove another param 2025-07-21 15:28:17 +02:00
Chris Kruining
d78e75e9c7
remove param 2025-07-21 15:27:12 +02:00
Chris Kruining
28f272b75b
spelling is an art... 2025-07-21 15:26:16 +02:00
Chris Kruining
7a7ceceead
fix gitversion config 2025-07-21 15:24:23 +02:00
Chris Kruining
253ad2e1bc
update gitversion 2025-07-21 15:20:20 +02:00
Chris Kruining
2a238bb835
Merge branch 'main' of https://github.com/chris-kruining/calque 2025-07-21 15:18:25 +02:00
Chris Kruining
1c31ef575a
update deps 2025-07-21 15:18:23 +02:00
f9c65835fd
Merge pull request #58 from chris-kruining/renovate/gittools-actions-4.x 2025-07-09 07:38:01 +02:00
renovate[bot]
8ae594d1f5
Update gittools/actions action to v4.0.1 2025-07-07 23:33:51 +00:00
bda74f01f9
Merge pull request #57 from chris-kruining/renovate/gittools-actions-4.x 2025-07-01 13:20:45 +02:00
renovate[bot]
ddcd451b49
Update gittools/actions action to v4 2025-06-30 10:58:03 +00:00
Chris Kruining
ce5b962e10
update deps 2025-06-23 16:23:17 +02:00
Chris Kruining
c58b597318
replace custom json parser with json.parse as it does preserve the key order after all, it is chrome devtools that sorts them 2025-06-23 16:19:45 +02:00
e7c0a762eb
Merge pull request #56 from chris-kruining/renovate/vitest-monorepo 2025-06-19 09:21:35 +02:00
renovate[bot]
01086b6e9b
Update vitest monorepo to v3.2.4 2025-06-17 20:13:51 +00:00
34eee3d2c1
Merge pull request #55 from chris-kruining/renovate/major-happy-dom-monorepo 2025-06-11 08:30:37 +02:00
renovate[bot]
01b65d337b
Update dependency @happy-dom/global-registrator to v18 2025-06-10 23:05:20 +00:00
c5f9fec9e9
Merge pull request #53 from chris-kruining/renovate/microsoft.resources-resourcegroups-20250401.x 2025-06-10 12:32:43 +02:00
2b749e4c63
Merge pull request #54 from chris-kruining/renovate/vitest-monorepo 2025-06-10 12:32:23 +02:00
renovate[bot]
24da21e722
Update vitest monorepo to v3.2.3 2025-06-09 12:11:48 +00:00
renovate[bot]
db04ee25e4
Update resource Microsoft.Resources/resourceGroups to 2025-04-01 2025-05-28 14:40:34 +00:00
24 changed files with 738 additions and 1212 deletions

View file

@ -27,25 +27,23 @@ jobs:
semver: ${{ steps.gitversion.outputs.SemVer }} semver: ${{ steps.gitversion.outputs.SemVer }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Install GitVersion - name: Install GitVersion
uses: gittools/actions/gitversion/setup@v3.2.1 uses: gittools/actions/gitversion/setup@v4.1.0
with: with:
versionSpec: "5.x" versionSpec: "6.x"
- name: Determine Version - name: Determine Version
id: gitversion id: gitversion
uses: gittools/actions/gitversion/execute@v3.2.1 uses: gittools/actions/gitversion/execute@v4.1.0
with:
useConfigFile: true
build_and_publish: build_and_publish:
name: Build & Publish name: Build & Publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: versionize needs: versionize
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- name: Build container images - name: Build container images
run: | run: |
@ -73,7 +71,7 @@ jobs:
matrix: matrix:
environment: [ 'prd' ] environment: [ 'prd' ]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
sparse-checkout: | sparse-checkout: |
infrastructure infrastructure
@ -86,13 +84,13 @@ jobs:
subscription-id: ${{ secrets.CALQUE_PRD_SUBSCRIPTION_ID }} subscription-id: ${{ secrets.CALQUE_PRD_SUBSCRIPTION_ID }}
- name: Deploy bicep - name: Deploy bicep
uses: Azure/cli@v2 uses: azure/cli@v2
with: with:
azcliversion: 2.66.0 azcliversion: 2.75.0
inlineScript: | inlineScript: >-
az deployment sub create \ az deployment sub create
--location westeurope \ --location westeurope
--template-file infrastructure/main.bicep \ --template-file infrastructure/main.bicep
--parameters infrastructure/params/${{ matrix.environment }}.bicepparam \ --parameters infrastructure/params/${{ matrix.environment }}.bicepparam
--parameters version=${{needs.versionize.outputs.semver}} \ --parameters version=${{needs.versionize.outputs.semver}}
--parameters registryUrl=${{ secrets.ACR_LOGIN_SERVER }} --parameters registryUrl=${{ secrets.ACR_LOGIN_SERVER }}

View file

@ -4,16 +4,17 @@ WORKDIR /usr/src/app
FROM base AS install FROM base AS install
RUN mkdir -p /temp/dev RUN mkdir -p /temp/dev
COPY package.json bun.lock /temp/dev COPY package.json bun.lock /temp/dev
COPY patches/ /temp/dev/patches/
RUN cd /temp/dev && bun install --frozen-lockfile RUN cd /temp/dev && bun install --frozen-lockfile
RUN mkdir -p /temp/prod RUN mkdir -p /temp/prod
COPY package.json bun.lock /temp/prod/ COPY package.json bun.lock /temp/prod/
COPY patches/ /temp/prod/patches/
RUN cd /temp/prod && bun install --frozen-lockfile --production RUN cd /temp/prod && bun install --frozen-lockfile --production
FROM base AS prerelease FROM base AS prerelease
COPY --from=install /temp/dev/node_modules node_modules COPY --from=install /temp/dev/node_modules node_modules
COPY . . COPY . .
# RUN echo "SESSION_SECRET=$(head -c 64 /dev/random | base64)" > .env
ENV NODE_ENV=production ENV NODE_ENV=production
ENV SERVER_PRESET=bun ENV SERVER_PRESET=bun

View file

@ -1,20 +0,0 @@
assembly-versioning-scheme: MajorMinorPatch
assembly-file-versioning-scheme: MajorMinorPatchTag
assembly-informational-format: "{InformationalVersion}"
mode: Mainline
tag-prefix: "[vV]"
continuous-delivery-fallback-tag: ci
major-version-bump-message: '\+semver:\s?(breaking|major)'
minor-version-bump-message: '\+semver:\s?(feature|minor)'
patch-version-bump-message: '\+semver:\s?(fix|patch)'
no-bump-message: '\+semver:\s?(none|skip)'
legacy-semver-padding: 4
build-metadata-padding: 4
commits-since-version-source-padding: 4
commit-message-incrementing: Enabled
branches: {}
ignore:
sha: []
increment: Inherit
commit-date-format: yyyy-MM-dd
merge-message-formats: {}

View file

@ -4,14 +4,29 @@ import devtools from 'solid-devtools/vite';
export default defineConfig({ export default defineConfig({
vite: { vite: {
resolve: {
alias: [
{ find: '@', replacement: 'F:\\Github\\calque\\node_modules\\' },
],
},
html: { html: {
cspNonce: 'KAAS_IS_AWESOME', cspNonce: 'KAAS_IS_AWESOME',
}, },
// css: {
// postcss: {
// },
// },
plugins: [ plugins: [
devtools({ devtools({
autoname: true, autoname: true,
}), }),
solidSvg(), solidSvg(),
{
name: 'temp',
configResolved(config) {
console.log(config.resolve.alias);
},
}
], ],
}, },
solid: { solid: {

1286
bun.lock

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@ var context = {
deployedAt: deployedAt deployedAt: deployedAt
} }
resource calqueResourceGroup 'Microsoft.Resources/resourceGroups@2025-03-01' = { resource calqueResourceGroup 'Microsoft.Resources/resourceGroups@2025-04-01' = {
name: 'rg-${locationAbbreviation}-${environment}-${projectName}' name: 'rg-${locationAbbreviation}-${environment}-${projectName}'
location: location location: location
} }

View file

@ -6,50 +6,50 @@
"bun": ">=1" "bun": ">=1"
}, },
"dependencies": { "dependencies": {
"@solid-primitives/clipboard": "^1.6.0", "@solid-primitives/clipboard": "^1.6.2",
"@solid-primitives/destructure": "^0.2.0", "@solid-primitives/destructure": "^0.2.2",
"@solid-primitives/i18n": "^2.2.0", "@solid-primitives/i18n": "^2.2.1",
"@solid-primitives/scheduled": "^1.5.0", "@solid-primitives/scheduled": "^1.5.2",
"@solid-primitives/selection": "^0.1.0", "@solid-primitives/selection": "^0.1.3",
"@solid-primitives/storage": "^4.3.1", "@solid-primitives/storage": "^4.3.3",
"@solid-primitives/timer": "^1.4.0", "@solid-primitives/timer": "^1.4.2",
"@solidjs/meta": "^0.29.4", "@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.3", "@solidjs/router": "^0.15.3",
"@solidjs/start": "^1.1.0", "@solidjs/start": "^1.1.7",
"dexie": "^4.0.11", "dexie": "^4.0.11",
"flag-icons": "^7.3.2", "flag-icons": "^7.5.0",
"iterator-helpers-polyfill": "^3.0.1", "iterator-helpers-polyfill": "^3.0.1",
"rehype-parse": "^9.0.1", "rehype-parse": "^9.0.1",
"rehype-remark": "^10.0.0", "rehype-remark": "^10.0.1",
"rehype-stringify": "^10.0.1", "rehype-stringify": "^10.0.1",
"remark-parse": "^11.0.0", "remark-parse": "^11.0.0",
"remark-rehype": "^11.1.1", "remark-rehype": "^11.1.2",
"remark-stringify": "^11.0.0", "remark-stringify": "^11.0.0",
"sitemap": "^8.0.0", "sitemap": "^8.0.0",
"solid-icons": "^1.1.0", "solid-icons": "^1.1.0",
"solid-js": "^1.9.4", "solid-js": "^1.9.7",
"ts-pattern": "^5.6.2", "ts-pattern": "^5.7.1",
"unified": "^11.0.5", "unified": "^11.0.5",
"unist-util-find": "^3.0.0", "unist-util-find": "^3.0.0",
"unist-util-visit": "^5.0.0", "unist-util-visit": "^5.0.0",
"vinxi": "^0.5.3" "vinxi": "^0.5.8"
}, },
"devDependencies": { "devDependencies": {
"@happy-dom/global-registrator": "^17.0.3", "@happy-dom/global-registrator": "^18.0.1",
"@sinonjs/fake-timers": "^14.0.0", "@sinonjs/fake-timers": "^14.0.0",
"@solidjs/testing-library": "^0.8.10", "@solidjs/testing-library": "^0.8.10",
"@testing-library/jest-dom": "^6.6.3", "@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^14.6.1", "@testing-library/user-event": "^14.6.1",
"@types/sinonjs__fake-timers": "^8.1.5", "@types/sinonjs__fake-timers": "^8.1.5",
"@types/wicg-file-system-access": "^2023.10.5", "@types/wicg-file-system-access": "^2023.10.6",
"@vitest/coverage-istanbul": "3.1.4", "@vitest/coverage-istanbul": "3.2.4",
"@vitest/coverage-v8": "3.1.4", "@vitest/coverage-v8": "3.2.4",
"bun-types": "^1.2.2", "bun-types": "^1.2.19",
"jsdom": "^26.0.0", "jsdom": "^26.1.0",
"solid-devtools": "^0.34.0", "solid-devtools": "^0.34.3",
"vite-plugin-solid": "^2.11.2", "vite-plugin-solid": "^2.11.7",
"vite-plugin-solid-svg": "^0.8.1", "vite-plugin-solid-svg": "^0.8.1",
"vitest": "^3.0.6", "vitest": "^3.2.4",
"workbox-window": "^7.3.0" "workbox-window": "^7.3.0"
}, },
"scripts": { "scripts": {

View file

@ -1,5 +0,0 @@
{
"provider_urls": [
"http://localhost:3000/auth/idp/api/config"
]
}

View file

@ -1,26 +0,0 @@
{
"accounts_endpoint": "/auth/idp/api/accounts",
"client_metadata_endpoint": "/auth/idp/api/metadata",
"id_assertion_endpoint": "/auth/idp/api/idtokens",
"disconnect_endpoint": "/auth/idp/api/disconnect",
"login_url": "/auth/idp",
"modes": {
"active": {
"supports_use_other_account": true
}
},
"branding": {
"background_color": "#6200ee",
"color": "#ffffff",
"icons": [
{
"url": "/images/favicon.dark.svg",
"size": 512
},
{
"url": "/images/favicon.light.svg",
"size": 512
}
]
}
}

View file

@ -1 +0,0 @@
Privacy Policy comes here.

View file

@ -1 +0,0 @@
Terms of Service comes here.

View file

@ -1,101 +0,0 @@
import { json, redirect } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
import { useSession } from "vinxi/http";
export type Middleware = (event: APIEvent) => Response | Promise<Response> | void | Promise<void> | Promise<void | Response>;
export interface User {
id: string;
username: string;
credential: string;
givenName: string;
familyName: string;
picture: string;
approvedClients: any[];
}
const USERS: User[] = [
{ id: '20d701f3-0f9f-4c21-a379-81b49f755f9e', username: 'chris', credential: 'test', givenName: 'Chris', familyName: 'Kruining', picture: '', approvedClients: [ '/auth/client' ] },
{ id: '10199201-1564-47db-b67b-07088ff05de8', username: 'john', credential: 'test', givenName: 'John', familyName: 'Doe', picture: '', approvedClients: [ '/auth/client' ] },
{ id: '633c44b3-8d3d-4dd1-8e1c-7de355d6dced', username: 'chris_alt', credential: 'test', givenName: 'Chris', familyName: 'Kruining', picture: '', approvedClients: [ '/auth/client' ] },
{ id: 'b9759798-8a41-4961-94a6-feb2372de9cf', username: 'john_alt', credential: 'test', givenName: 'John', familyName: 'Doe', picture: '', approvedClients: [ '/auth/client' ] },
];
export const getUser = (idOrUsername: string) => {
return USERS.find(u => u.id === idOrUsername || u.username === idOrUsername);
};
export const signIn = async (user: User) => {
const { update } = await useSession<{ signedIn?: boolean, id?: string }>({
password: process.env.SESSION_SECRET!,
});
await update({ signedIn: true, id: user.id });
};
export const signOut = async () => {
const { update } = await useSession<{ signedIn?: boolean, id?: string }>({
password: process.env.SESSION_SECRET!,
});
await update({});
};
export const use = (...middlewares: Middleware[]) => {
return async (event: APIEvent) => {
console.log(`received ${event.request.url}`);
for (const handler of middlewares) {
const response = await handler(event);
console.log(response?.status);
if (response !== undefined) {
return response;
}
}
};
};
export const assertCsrf: Middleware = async ({ request }: APIEvent) => {
if (request.headers.get('Sec-Fetch-Dest') !== 'webidentity') {
console.log('request failed the csrf test');
return json({ error: 'Invalid access' }, { status: 400 });
}
};
export const assertSession: Middleware = async ({ request, locals }: APIEvent) => {
const user = await getSession();
if (user === undefined) {
console.log('user session not available');
return redirect('/auth/idp', { status: 401 });
}
locals.user = user;
};
export const assertApiSession = async ({ request, locals }: APIEvent) => {
const user = await getSession();
if (user === undefined) {
console.log('user session not available');
return json({ error: 'not signed in' }, { status: 401 });
}
locals.user = user;
};
const getSession = async () => {
const { data } = await useSession<{ signedIn?: boolean, id?: string }>({
password: process.env.SESSION_SECRET!,
});
if (data.signedIn !== true) {
return;
}
return USERS.find(u => u.id === data.id);
};

View file

@ -12,7 +12,7 @@ interface Contents extends Map<string, Map<string, string>> { }
export const read = (file: File): Promise<Map<string, string> | undefined> => { export const read = (file: File): Promise<Map<string, string> | undefined> => {
switch (file.type) { switch (file.type) {
case 'application/json': return json.load(file.stream()); case 'application/json': return json.load(file.text());
default: return Promise.resolve(undefined); default: return Promise.resolve(undefined);
} }

View file

@ -1,200 +1,20 @@
import { decode } from "~/utilities"; import { decode } from "~/utilities";
export async function load(stream: ReadableStream<Uint8Array>): Promise<Map<string, string>> { export async function load(text: Promise<string>): Promise<Map<string, string>> {
return new Map(await Array.fromAsync(parse(stream), ({ key, value }) => [key, value])); const source = JSON.parse(await text);
} const result = new Map();
const candidates = Object.entries(source);
interface Entry { while (candidates.length !== 0) {
key: string; const [ key, value ] = candidates.shift()!;
value: string;
}
interface State { if (typeof value !== 'object' || value === null || value === undefined) {
(token: Token): State; result.set(key, decode(value as string));
entry?: Entry
}
const states = {
none(): State {
return (token: Token) => {
if (token.kind === 'braceOpen') {
return states.object();
}
return states.none;
};
},
object({ path = [], expect = 'key' }: Partial<{ path: string[], expect: 'key' | 'colon' | 'value' }> = {}): State {
return (token: Token) => {
switch (expect) {
case 'key': {
if (token.kind === 'braceClose') {
return states.object({
path: path.slice(0, -1),
expect: 'key',
});
}
else if (token.kind === 'string') {
return states.object({
path: [...path, token.value],
expect: 'colon'
});
}
return states.error(`Expected a key, got ${token.kind} instead`);
}
case 'colon': {
if (token.kind !== 'colon') {
return states.error(`Expected a ':', got ${token.kind} instead`);
}
return states.object({
path,
expect: 'value'
});
}
case 'value': {
if (token.kind === 'braceOpen') {
return states.object({
path,
expect: 'key',
});
}
else if (token.kind === 'string') {
const next = states.object({
path: path.slice(0, -1),
expect: 'key',
});
next.entry = { key: path.join('.'), value: decode(token.value) };
return next
}
return states.error(`Invalid value type found '${token.kind}'`);
}
}
return states.none();
} }
}, else {
error(message: string): State { candidates.unshift(...Object.entries(value).map<[string, any]>(([ k, v ]) => [`${key}.${k}`, v]));
throw new Error(message);
return states.none();
},
} as const;
async function* parse(stream: ReadableStream<Uint8Array>): AsyncGenerator<any, void, unknown> {
let state = states.none();
for await (const token of tokenize(read(toGenerator(stream)))) {
try {
state = state(token);
}
catch (e) {
console.error(e);
break;
}
if (state.entry) {
yield state.entry;
} }
} }
}
async function* take<T>(iterable: AsyncIterable<T>, numberToTake: number): AsyncGenerator<T, void, unknown> { return result;
let i = 0;
for await (const entry of iterable) {
yield entry;
i++;
if (i === numberToTake) {
break;
}
}
}
type Token = { start: number, length: number } & (
| { kind: 'braceOpen' }
| { kind: 'braceClose' }
| { kind: 'colon' }
| { kind: 'string', value: string }
);
async function* tokenize(characters: AsyncIterable<number>): AsyncGenerator<Token, void, unknown> {
let buffer: string = '';
let clearBuffer = false;
let start = 0;
let i = 0;
for await (const character of characters) {
if (buffer.length === 0) {
start = i;
}
buffer += String.fromCharCode(character);
const length = buffer.length;
if (buffer === '{') {
yield { kind: 'braceOpen', start, length };
clearBuffer = true;
}
else if (buffer === '}') {
yield { kind: 'braceClose', start, length };
clearBuffer = true;
}
else if (buffer === ':') {
yield { kind: 'colon', start, length };
clearBuffer = true;
}
else if (buffer.length > 1 && buffer.startsWith('"') && buffer.endsWith('"') && buffer.at(-2) !== '\\') {
yield { kind: 'string', start, length, value: buffer.slice(1, buffer.length - 1) };
clearBuffer = true;
}
else if (buffer === ',') {
clearBuffer = true;
}
else if (buffer.trim() === '') {
clearBuffer = true;
}
if (clearBuffer) {
buffer = '';
clearBuffer = false;
}
i++;
}
}
async function* read(chunks: AsyncIterable<Uint8Array>): AsyncGenerator<number, void, unknown> {
for await (const chunk of chunks) {
for (const character of chunk) {
yield character;
}
}
}
async function* toGenerator<T>(stream: ReadableStream<T>): AsyncGenerator<T, void, unknown> {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
yield value;
}
}
finally {
reader.releaseLock();
}
} }

View file

@ -1,33 +0,0 @@
import { onMount } from "solid-js";
export default function Index() {
onMount(async () => {
const user = await fetch('/auth/idp/api/user-info').then(r => r.json());
console.log(user);
if (user === undefined || true) {
try {
const credential = await navigator.credentials.get({
identity: {
providers: [{
configURL: new URL('http://localhost:3000/auth/idp/api/config'),
clientId: '/auth/client',
nonce: 'kaas',
loginHint: 'chris',
}],
mode: 'passive',
context: undefined,
},
mediation: 'silent',
});
console.log(credential);
} catch(e) {
console.error(e);
}
}
});
return 'WOOT';
}

View file

@ -1,8 +0,0 @@
import { json } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
export const GET = ({ request }: APIEvent) => {
console.error(`url not found ${request.url}`);
return json({ error: `url ${request.url} is not implemented` }, { status: 404 })
};

View file

@ -1,23 +0,0 @@
import { json } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
import { assertApiSession, assertCsrf, use, User } from "~/features/auth";
export const GET = use(assertCsrf, assertApiSession, async ({ locals }: APIEvent) => {
const { user } = locals;
console.log('accounts endpoint', user);
return json({
accounts: [
{
id: user.id,
given_name: user.givenName,
name: `${user.givenName} ${user.familyName}`,
email: user.username,
picture: user.picture,
login_hints: [user.username],
approved_clients: user.approvedClients,
}
],
});
});

View file

@ -1,33 +0,0 @@
import { json } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
export const GET = async ({ request }: APIEvent) => {
console.log('config requested', request);
return json({
"accounts_endpoint": "/auth/idp/api/accounts",
"client_metadata_endpoint": "/auth/idp/api/metadata",
"id_assertion_endpoint": "/auth/idp/api/idtokens",
"disconnect_endpoint": "/auth/idp/api/disconnect",
"login_url": "/auth/idp",
"modes": {
"active": {
"supports_use_other_account": true
}
},
"branding": {
"background_color": "#6200ee",
"color": "#ffffff",
"icons": [
{
"url": "/images/favicon.dark.svg",
"size": 512
},
{
"url": "/images/favicon.light.svg",
"size": 512
}
]
}
});
};

View file

@ -1,11 +0,0 @@
import { json } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
import { use, assertCsrf, assertApiSession } from "~/features/auth";
export const POST = use(assertCsrf, assertApiSession, async ({ request, locals }: APIEvent) => {
console.log(locals, request);
return json({
account_id: locals.user.id,
});
});

View file

@ -1,15 +0,0 @@
import { json } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
import { use, assertCsrf, assertApiSession } from "~/features/auth";
export const POST = use(assertCsrf, assertApiSession, async ({ request }: APIEvent) => {
console.log('id token requested', request.url);
return json({
token: 'THIS IS A BEAUTIFUL TOKEN',
}, {
headers: {
'Set-Login': 'logged-in'
}
});
});

View file

@ -1,39 +0,0 @@
import { json, redirect } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
import { getUser, signIn } from "~/features/auth";
export const POST = async ({ request }: APIEvent) => {
console.log('login requested', request.url);
const formData = await request.formData();
const username = formData.get('username');
const password = formData.get('password');
if (typeof username !== 'string' || /^[a-z0-9-_]+$/.test(username) !== true) {
return json({ error: 'Bad request' }, { status: 400 })
}
if (typeof password !== 'string' || password.length === 0) {
return json({ error: 'Bad request' }, { status: 400 })
}
const user = getUser(username);
if (user === undefined) {
return json({ error: 'Invalid credentials' }, { status: 400 });
}
if (user.credential !== password) {
return json({ error: 'Invalid credentials' }, { status: 400 });
}
await signIn(user);
const token = 'THIS IS MY AWESOME TOKEN';
return json({ token }, {
headers: {
'Set-Login': 'logged-in',
}
});
};

View file

@ -1,12 +0,0 @@
import { json } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
export const GET = ({ request }: APIEvent) => {
console.log('metadata requested', request.url);
return json({
privacy_policy_url: '/privacy-policy.txt',
terms_of_service_url: '/terms-of-service.txt',
icons: []
});
};

View file

@ -1,17 +0,0 @@
import { json } from "@solidjs/router";
import { APIEvent } from "@solidjs/start/server";
import { assertApiSession, use } from "~/features/auth";
export const GET = use(assertApiSession, async ({ locals }: APIEvent) => {
const { user } = locals;
return json({
id: user.id,
given_name: user.givenName,
name: `${user.givenName} ${user.familyName}`,
email: user.username,
picture: user.picture,
login_hints: [user.username],
approved_clients: user.approvedClients,
});
});

View file

@ -1,17 +0,0 @@
import { useParams, useSearchParams } from "@solidjs/router"
export default function Login() {
const [params] = useSearchParams();
return <div>
<h1>Login</h1>
<form method="post" action="/auth/idp/api/login">
<label>username: <input type="text" name="username" value={params.login_hint} /></label>
<label>password: <input type="password" name="password" value="test" /></label>
<button type="submit">Submit</button>
</form>
</div>
}