ekyc

Electronic KYC process with uploading ID document using OAuth 2.1 (experimental)
Log | Files | Refs | README | LICENSE

oauth2_flow.ts (3820B)


      1 import { OAuth2FlowRepository } from "#core/application/oauth2/flow_repository.ts";
      2 import {
      3   EntityLocked,
      4   EntityNotFound,
      5 } from "#core/application/repository_error.ts";
      6 import { OAuth2Flow } from "#core/domain/oauth2flow.ts";
      7 import { Token } from "#core/domain/token.ts";
      8 import { UUID } from "#core/domain/uuid.ts";
      9 import {
     10   mapFromOAuth2Flow,
     11   mapToOAuth2Flow,
     12   OAuth2FlowDto,
     13 } from "#infrastructure/memory/mapper/oauth2flow.ts";
     14 import { mapError } from "#infrastructure/postgres/error.ts";
     15 import { Pool } from "$postgres";
     16 
     17 export class PostgresOAuth2FlowRepositoryAdapter
     18   implements OAuth2FlowRepository {
     19   constructor(readonly pool: Pool) {
     20   }
     21 
     22   async find(uuid: UUID): Promise<OAuth2Flow> {
     23     try {
     24       const connection = await this.pool.connect();
     25       try {
     26         const result = await connection.queryObject<
     27           OAuth2FlowDto
     28         >`select * from "oauth2flow" where "uuid" = ${uuid.toString()} limit 1;`;
     29         if (result.rowCount !== 1) {
     30           throw new EntityNotFound(uuid.toString());
     31         }
     32         return mapToOAuth2Flow(result.rows[0]);
     33       } finally {
     34         connection.release();
     35       }
     36     } catch (error) {
     37       throw mapError(error);
     38     }
     39   }
     40 
     41   async findByToken(token: Token): Promise<OAuth2Flow> {
     42     try {
     43       const connection = await this.pool.connect();
     44       try {
     45         const result = await connection.queryObject<
     46           OAuth2FlowDto
     47         >`select * from "oauth2flow" where "token" = ${token.toString()} limit 1;`;
     48         if (result.rowCount !== 1) {
     49           throw new EntityNotFound(token.toString());
     50         }
     51         return mapToOAuth2Flow(result.rows[0]);
     52       } finally {
     53         connection.release();
     54       }
     55     } catch (error) {
     56       throw mapError(error);
     57     }
     58   }
     59 
     60   async store(flow: OAuth2Flow): Promise<void> {
     61     try {
     62       const dto = mapFromOAuth2Flow(flow);
     63       const connection = await this.pool.connect();
     64       const transaction = connection.createTransaction(
     65         `txn_${dto.uuid}_${dto.version}`,
     66       );
     67       try {
     68         await transaction.begin();
     69         await transaction
     70           .queryArray`delete from "oauth2flow" where created < (current_timestamp - interval '1 day');`;
     71 
     72         dto.version++;
     73         if (dto.version === 1) {
     74           await transaction.queryObject<void>`
     75             insert into "oauth2flow" (
     76               "uuid", "clientId", "scope", "state",
     77               "resourceOwner", "token", "tokenExpire",
     78               "version"
     79             ) values (
     80               ${dto.uuid}, ${dto.clientId}, ${dto.scope}, ${dto.state},
     81               ${dto.resourceOwner}, ${dto.token}, ${dto.tokenExpire},
     82               ${dto.version}
     83             );
     84         `;
     85           await transaction.commit();
     86           flow.version = dto.version;
     87           return;
     88         }
     89         const result = await transaction.queryObject<{ version: number }>`
     90             update "oauth2flow" set
     91               "uuid" = ${dto.uuid},
     92               "clientId" = ${dto.clientId},
     93               "scope" = ${dto.scope},
     94               "state" = ${dto.state},
     95               "resourceOwner" = ${dto.resourceOwner},
     96               "token" = ${dto.token},
     97               "tokenExpire" = ${dto.tokenExpire},
     98               "version" = "version" + 1
     99             where uuid = ${dto.uuid}
    100             returning version;
    101         `;
    102         if (result.rowCount !== 1) {
    103           transaction.rollback();
    104           throw new EntityNotFound(dto.uuid);
    105         }
    106         if (result.rows[0].version === dto.version) {
    107           await transaction.commit();
    108           flow.version = result.rows[0].version;
    109           return;
    110         }
    111         transaction.rollback();
    112         throw new EntityLocked();
    113       } finally {
    114         connection.release();
    115       }
    116     } catch (error) {
    117       throw mapError(error);
    118     }
    119   }
    120 }