diff options
Diffstat (limited to 'app/src/routes/sb1.remote.ts')
| -rw-r--r-- | app/src/routes/sb1.remote.ts | 192 |
1 files changed, 27 insertions, 165 deletions
diff --git a/app/src/routes/sb1.remote.ts b/app/src/routes/sb1.remote.ts index 17e1ead..d2eb0cc 100644 --- a/app/src/routes/sb1.remote.ts +++ b/app/src/routes/sb1.remote.ts @@ -1,181 +1,43 @@ -import { SB1_FIN_INST, SB1_ID, SB1_REDIRECT_URI, SB1_SECRET } from "$env/static/private"; -import { randomUUID } from "node:crypto"; -import { db } from "../lib/server/db"; -import { syncSession } from "../lib/server/db/schema"; +import { db } from "$lib/server/db"; +import { syncSession } from "$lib/server/db/schema"; import * as v from "valibot" import { command, query } from "$app/server"; -import { eq } from "drizzle-orm"; -import { Temporal } from "temporal-polyfill"; +import sb1 from "$lib/server/sb1"; -export const createSb1SyncSessionAndReturnLoginUrl = command(async () => { - return createSb1Auth() +const init_auth_session = command(async () => { + return await sb1.auth.init_auth_session() }) -async function createSb1Auth() { - const state = randomUUID() - - await db.insert(syncSession).values({ - authzState: state - }) - - const authorizeUrl = new URL("https://api.sparebank1.no/oauth/authorize"); - - authorizeUrl.searchParams.set("client_id", SB1_ID); - authorizeUrl.searchParams.set("state", state); - authorizeUrl.searchParams.set("redirect_uri", SB1_REDIRECT_URI); - authorizeUrl.searchParams.set("finInst", SB1_FIN_INST); - authorizeUrl.searchParams.set("response_type", "code"); - - return authorizeUrl.toString() -} - -export const getAccounts = query(async () => { - const token = await getSb1AccessToken() - if (!token) return undefined - const url = new URL( - "https://api.sparebank1.no/personal/banking/accounts", - ); - const response = await fetch(url, { - headers: { - Authorization: `Bearer ${token}` - }, - }); - if (response.ok) { - return await response.json() as { accounts: Array<any> } - } - else console.error(await response.text()) +const is_ready = query(async () => { + return await sb1.auth.is_ready() }) -export const getTransactions = query(v.string(), async (accountKey: string) => { - const token = await getSb1AccessToken() - if (token) return undefined - const url = new URL( - "https://api.sparebank1.no/personal/banking/transactions", - ); - url.searchParams.set("accountKey", accountKey); - const response = await fetch(url, { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - return (await response.json()) as TransactionsResponse; +const get_accounts = query(async () => { + return await sb1.data.get_accounts() }) -async function getSb1AccessToken() { - const entity = await db.select({ - tokens: syncSession.tokens - }).from(syncSession) - const { tokens } = entity[0] - if (!tokens) return null - const parsed = JSON.parse(tokens) - return parsed.access_token as string -} +const get_transactions = query(v.string(), async (accountKey: string) => { + return await sb1.data.get_transactions(accountKey) +}) -export const clearTokens = query(async () => { +const clear_auth_session = query(async () => { await db.delete(syncSession) }) -export const getTokenExpires = query(async () => { - const entity = await db.select({ - refreshTokenCreated: syncSession.refreshTokenCreated, - accessTokenCreated: syncSession.accessTokenCreated, - tokens: syncSession.tokens - }).from(syncSession) - if (!entity[0]) return undefined - const { tokens, accessTokenCreated, refreshTokenCreated } = entity[0] - const tokensParsed = JSON.parse(tokens ?? "") - return { - accessToken: { - expires: tokensParsed?.expires_in ?? 0, - created: Temporal.Instant.fromEpochMilliseconds(Number(accessTokenCreated)) - }, - refreshToken: { - expires: tokensParsed?.refresh_token_expires_in ?? 0, - created: Temporal.Instant.fromEpochMilliseconds(Number(refreshTokenCreated)) - }, - } +const get_auth_info = query(async () => { + return await sb1.auth.get_auth_info() }) -type Sb1Tokens = { - access_token: string, - expires_in: number, - refresh_token_expires_in: number, - refresh_token_absolute_expires_in: number, - token_type: string, - refresh_token: string -} - -type TokenAction = "Empty" - -const auth = { - async ready(): Promise<boolean> { - const token = await this.tokenOrAction() - const ping = await fetch("https://developer.sparebank1.no/helloworld/ping", { - headers: { - "Authorization": "Bearer " + token - } - }) - return ping.ok - }, - async tokenOrAction(): Promise<TokenAction | string> { - const entity = await db.select({ - refreshTokenCreated: syncSession.refreshTokenCreated, - accessTokenCreated: syncSession.accessTokenCreated, - tokens: syncSession.tokens - }).from(syncSession) - const { tokens, accessTokenCreated, refreshTokenCreated } = entity[0] - if (!tokens) return "Empty" - const json = JSON.parse(tokens) as Sb1Tokens - if (!Object.hasOwn(json, "access_token")) return TokenAction.Empty - return json.access_token - }, - getAccessToken() { }, - async getRefreshToken() { - const entity = await db.select({ - tokens: syncSession.tokens, - id: syncSession.id - }).from(syncSession) - - const { tokens, id } = entity[0] - - if (!tokens) return null - - const parsed = JSON.parse(tokens) - - if (!parsed.refresh_token) throw new Error("No refresh token"); - - const fd = new URLSearchParams(); - - fd.set("client_id", SB1_ID); - fd.set("client_secret", SB1_SECRET); - fd.set("refresh_token", parsed.refresh_token); - fd.set("grant_type", "refresh_token"); - - const res = await fetch("https://api.sparebank1.no/oauth/token", { - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - method: "post", - body: fd, - }); - - const text = await res.text(); - const epoch = Temporal.Now.instant().epochMilliseconds - await db.update(syncSession).set({ tokens: text, accessTokenCreated: epoch, refreshTokenCreated: epoch }).where(eq(syncSession.id, id)) - } -} - -export const refreshSB1Token = command(async () => { - auth.getRefreshToken() -}); - -export type Transaction = { - description: string; - amount: number; - date: string; - mcc: string; -} +const refresh_tokem = command(async () => { + await sb1.auth.refresh_tokem() +}) -export type TransactionsResponse = { - transactions: Array<Transaction>; -} +export { + refresh_tokem, + init_auth_session, + is_ready, + get_accounts, + get_transactions, + clear_auth_session, + get_auth_info, +}
\ No newline at end of file |
