diff --git a/.env.sample b/.env.sample index 4d312ef..7c7bb45 100644 --- a/.env.sample +++ b/.env.sample @@ -12,4 +12,5 @@ DOMAIN=verify.sealcred.xyz ENVIRONMENT=development MAILGUN_API_KEY=00000000000000000000000000000000 MAILGUN_DOMAIN=example.com -KETL_INVITES_BACKEND=https://example.com \ No newline at end of file +KETL_INVITES_BACKEND=https://example.com +SECRET=secret \ No newline at end of file diff --git a/README.md b/README.md index d497af3..975af03 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ And you should be good to go! Feel free to fork and submit pull requests. | `KETL_INVITES_BACKEND` | Link to merkle tree hashes for Ketl | | `MAILGUN_API_KEY` | Mailgun API key | | `MAILGUN_DOMAIN` | Mailgun Domain | +| `SECRET` | Bearer token | Also, please, consider looking at `.env.sample`. diff --git a/src/controllers/verify-ketl.ts b/src/controllers/verify-ketl.ts index 21dc6e3..292a317 100644 --- a/src/controllers/verify-ketl.ts +++ b/src/controllers/verify-ketl.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Ctx, Post, Version } from 'amala' +import { Body, Controller, Ctx, Flow, Post, Version } from 'amala' import { Context } from 'vm' import { KETL_BWL_NFT_CONTRACT, @@ -11,10 +11,12 @@ import AttestationType from '@/validators/AttestationType' import AttestationTypeList from '@/validators/AttestationTypeList' import BalanceUniqueVerifyBody from '@/validators/BalanceUniqueVerifyBody' import Email from '@/validators/Email' +import SignValidator from '@/validators/SignValidator' import Signature from '@/validators/Signature' import Token from '@/validators/Token' import TwitterBody from '@/validators/TwitterBody' import VerificationType from '@/models/VerificationType' +import authenticate from '@/helpers/authenticate' import checkInvite from '@/helpers/ketl/checkInvite' import fetchUserProfile from '@/helpers/twitter/fetchUserProfile' import getAttestationHash from '@/helpers/signatures/getAttestationHash' @@ -50,6 +52,38 @@ export default class VerifyKetlController { return signAttestationMessage(type, hexlifyString(token)) } + @Post('/sign') + @Flow(authenticate) + @Version('0.2.2') + async sign( + @Ctx() ctx: Context, + @Body({ required: true }) + body: SignValidator + ) { + const { hash, types } = body + const secretParts = [] + + for (const type of types) { + const { message, signature } = await signAttestationMessage(type, hash) + const hasInvite = await checkInvite(type, hash) + if (!hasInvite) continue + if (secretParts.length === 0) { + const attestationHash = message[1] + secretParts.push(attestationHash) + } + secretParts.push(`t${type}${signature}`) + } + + if (!secretParts.length) + return ctx.throw(notFound(handleInvitationError('email'))) + + const secret = secretParts.join('') + + return { + secret, + } + } + @Post('/email-unique') @Version('0.2.2') async sendMultipleEmailAttestation( diff --git a/src/helpers/authenticate.ts b/src/helpers/authenticate.ts new file mode 100644 index 0000000..7b7b126 --- /dev/null +++ b/src/helpers/authenticate.ts @@ -0,0 +1,13 @@ +import { Context, Next } from 'koa' +import { forbidden } from '@hapi/boom' +import verifyAuthToken from '@/helpers/verifyAuthToken' + +export default async function authenticate(ctx: Context, next: Next) { + const authHeader = ctx.headers.authorization + const token = authHeader && authHeader.split(' ')[1] + const isValidToken = await verifyAuthToken(token) + + if (!isValidToken) throw forbidden() + + return next() +} diff --git a/src/helpers/env.ts b/src/helpers/env.ts index 79a5307..31b9f99 100644 --- a/src/helpers/env.ts +++ b/src/helpers/env.ts @@ -27,6 +27,7 @@ export default cleanEnv(process.env, { MAILGUN_API_KEY: str(), MAILGUN_DOMAIN: str(), PORT: num({ default: 1337 }), + SECRET: str(), SMTP_PASS: str(), SMTP_USER: str(), }) diff --git a/src/helpers/verifyAuthToken.ts b/src/helpers/verifyAuthToken.ts new file mode 100644 index 0000000..428a6b7 --- /dev/null +++ b/src/helpers/verifyAuthToken.ts @@ -0,0 +1,11 @@ +import env from '@/helpers/env' + +export default function verifyAuthToken(authToken?: string) { + if (!authToken) return false + try { + return env.SECRET === authToken + } catch (e) { + console.log(e) + return false + } +} diff --git a/src/validators/SignValidator.ts b/src/validators/SignValidator.ts new file mode 100644 index 0000000..6f45944 --- /dev/null +++ b/src/validators/SignValidator.ts @@ -0,0 +1,10 @@ +import { IsEnum, IsString } from 'amala' +import AttestationType from '@/models/AttestationType' + +export default class { + @IsString() + hash!: string + + @IsEnum(AttestationType, { each: true }) + types!: AttestationType[] +}