chore: clean & rename some api funcs

This commit is contained in:
MTG2000
2022-06-11 12:05:16 +03:00
parent dc6d462c18
commit 28549df6d4
6 changed files with 123 additions and 110 deletions

View File

@@ -3,24 +3,24 @@ const crypto = require('crypto')
const { prisma } = require('../../prisma') const { prisma } = require('../../prisma')
const { CONSTS } = require('../../utils') const { CONSTS } = require('../../utils')
async function generateSecret() { async function generateK1() {
let secret = null let k1 = null
const maxAttempts = 5 const maxAttempts = 5
let attempt = 0 let attempt = 0
while (secret === null && attempt < maxAttempts) { while (k1 === null && attempt < maxAttempts) {
secret = crypto.randomBytes(32).toString('hex') k1 = crypto.randomBytes(32).toString('hex')
const hash = createHash(secret) const hash = createHash(k1)
const isUsed = await isHashUsed(hash); const isUsed = await isHashUsed(hash);
if (isUsed) { if (isUsed) {
secret = null k1 = null
} }
attempt++ attempt++
} }
if (!secret) { if (!k1) {
const message = 'Too many failed attempts to generate unique secret' const message = 'Too many failed attempts to generate unique k1'
throw new Error(message) throw new Error(message)
} }
return secret return k1
} }
function isHashUsed(hash) { function isHashUsed(hash) {
@@ -58,7 +58,7 @@ function removeExpiredHashes() {
async function generateAuthUrl() { async function generateAuthUrl() {
const hostname = CONSTS.LNURL_AUTH_HOST; const hostname = CONSTS.LNURL_AUTH_HOST;
const secret = await generateSecret(); const secret = await generateK1();
const hash = createHash(secret); const hash = createHash(secret);
await addHash(hash) await addHash(hash)
const url = `${hostname}?tag=login&k1=${secret}` const url = `${hostname}?tag=login&k1=${secret}`

View File

@@ -0,0 +1,57 @@
const LnurlAuthService = require('../../auth/services/lnurlAuth.service')
const serverless = require('serverless-http');
const { createExpressApp } = require('../../modules');
const express = require('express');
const jose = require('jose');
const { JWT_SECRET } = require('../../utils/consts');
const getLoginUrl = async (req, res) => {
try {
const data = await LnurlAuthService.generateAuthUrl();
const maxAge = 1000 * 60 * 3; //2 mins
const jwt = await new jose.SignJWT({ hash: data.secretHash })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('5min')
.sign(Buffer.from(JWT_SECRET, 'utf-8'))
return res
.status(200)
.cookie('login_session', jwt, {
maxAge,
secure: true,
httpOnly: true,
sameSite: "none",
})
.json(data);
} catch (error) {
console.log(error);
res.status(500).send("Unexpected error happened, please try again")
}
}
let app;
if (process.env.LOCAL) {
app = createExpressApp()
app.get('/get-login-url', getLoginUrl);
}
else {
const router = express.Router();
router.get('/get-login-url', getLoginUrl)
app = createExpressApp(router)
}
const handler = serverless(app);
exports.handler = async (event, context) => {
return await handler(event, context);
};

View File

@@ -1,28 +1,26 @@
const serverless = require('serverless-http'); const serverless = require('serverless-http');
const { getAuthTokenByHash } = require('../../auth/services/lnurl.service');
const { createExpressApp } = require('../../modules'); const { createExpressApp } = require('../../modules');
const express = require('express'); const express = require('express');
const jose = require('jose'); const jose = require('jose');
const { JWT_SECRET } = require('../../utils/consts'); const { JWT_SECRET } = require('../../utils/consts');
const lnurlService = require('../../auth/services/lnurl.service'); const lnurlAuthService = require('../../auth/services/lnurlAuth.service');
const isLoggedInHandler = async (req, res) => { const isLoggedInHandler = async (req, res) => {
try { try {
const login_session = req.cookies?.login_session; const login_session = req.cookies?.login_session;
if (login_session) { if (login_session) {
const { payload } = await jose.jwtVerify(login_session, Buffer.from(JWT_SECRET), { const { payload } = await jose.jwtVerify(login_session, Buffer.from(JWT_SECRET), {
algorithms: ['HS256'], algorithms: ['HS256'],
}); });
const hash = payload.hash; const hash = payload.hash;
const token = await getAuthTokenByHash(hash); const authToken = await lnurlAuthService.getAuthTokenByHash(hash);
if (!token) if (!authToken)
throw new Error("Not logged in yet") throw new Error("Not logged in yet")
lnurlService.removeHash(hash).catch(); lnurlAuthService.removeHash(hash).catch();
lnurlService.removeExpiredHashes().catch(); lnurlAuthService.removeExpiredHashes().catch();
res res
.status(200) .status(200)
@@ -31,7 +29,7 @@ const isLoggedInHandler = async (req, res) => {
httpOnly: true, httpOnly: true,
sameSite: "none", sameSite: "none",
}) })
.cookie('Authorization', token, { .cookie('Authorization', authToken, {
maxAge: 3600000 * 24 * 30, maxAge: 3600000 * 24 * 30,
secure: true, secure: true,
httpOnly: true, httpOnly: true,
@@ -42,24 +40,16 @@ const isLoggedInHandler = async (req, res) => {
}); });
} else { } else {
res.json({ res.json({
me: null logged_in: false
}); });
} }
} catch (error) { } catch (error) {
console.log(error);
res.json({ res.json({
logged_in: false logged_in: false
}) })
} }
// get session token
// check DB to see if this token has an accossiated jwt auth token to it
// if yes:
// set the auth token to cookie
// remove the session token
// remove the data row
} }

View File

@@ -1,8 +1,8 @@
const { prisma } = require('../../prisma'); const { prisma } = require('../../prisma');
const LnurlService = require('../../auth/services/lnurl.service') const LnurlAuthService = require('../../auth/services/lnurlAuth.service')
const serverless = require('serverless-http'); const serverless = require('serverless-http');
const { createHash, associateTokenToHash } = require('../../auth/services/lnurl.service'); const { createHash, associateTokenToHash } = require('../../auth/services/lnurlAuth.service');
const { createExpressApp } = require('../../modules'); const { createExpressApp } = require('../../modules');
const express = require('express'); const express = require('express');
const jose = require('jose'); const jose = require('jose');
@@ -10,92 +10,55 @@ const { JWT_SECRET } = require('../../utils/consts');
const router = express.Router();
router.get('/login', (req, res) => {
res.cookie('login_session', 'value', {
maxAge: 1000 * 60 * 2, // 2 mins
secure: true,
httpOnly: true,
sameSite: "none",
})
})
const loginHandler = async (req, res) => { const loginHandler = async (req, res) => {
const { tag, k1, sig, key } = req.query; const { tag, k1, sig, key } = req.query;
// Generate an auth URL
if (!sig || !key) {
const data = await LnurlService.generateAuthUrl();
const maxAge = 1000 * 60 * 3; //2 mins
const jwt = await new jose.SignJWT({ hash: data.secretHash }) if (tag !== 'login')
return res.status(400).json({ status: 'ERROR', reason: 'Invalid Tag Provided' })
// Verify login params
try {
await LnurlAuthService.verifySig(sig, k1, key)
} catch (error) {
return res.status(400).json({ status: 'ERROR', reason: 'Invalid Signature' })
}
try {
//Create user if not already existing
const user = await prisma.user.findFirst({ where: { pubKey: key } })
if (user === null) {
await prisma.user.create({
data: {
pubKey: key,
name: key,
avatar: `https://avatars.dicebear.com/api/bottts/${key}.svg`
}
})
}
// calc the hash of k1
const hash = createHash(k1);
// generate the auth jwt token
const hour = 3600000
const maxAge = 30 * 24 * hour;
const authToken = await new jose.SignJWT({ pubKey: key })
.setProtectedHeader({ alg: 'HS256' }) .setProtectedHeader({ alg: 'HS256' })
.setIssuedAt() .setIssuedAt()
.setExpirationTime('5min') .setExpirationTime(maxAge)
//TODO: Set audience, issuer
.sign(Buffer.from(JWT_SECRET, 'utf-8')) .sign(Buffer.from(JWT_SECRET, 'utf-8'))
return res // associate the auth token with the hash in the db
.status(200) await associateTokenToHash(hash, authToken);
.cookie('login_session', jwt, {
maxAge,
secure: true,
httpOnly: true,
sameSite: "none",
})
.json(data);
}
else {
if (tag !== 'login')
return res.status(400).send("Invalid tag provided")
// Verify login params
try {
await LnurlService.verifySig(sig, k1, key)
} catch (error) {
return res.status(400).json({ status: 'ERROR', reason: 'Invalid Signature' })
}
try { return res.status(200).json({ status: "OK" })
//Create user if not already existing
const user = await prisma.user.findFirst({ where: { pubKey: key } })
if (user === null) {
await prisma.user.create({
data: {
pubKey: key,
name: key,
avatar: `https://avatars.dicebear.com/api/bottts/${key}.svg`
}
})
}
// calc the hash of k1 } catch (error) {
const hash = createHash(k1); return res.status(400).json({ status: 'ERROR', reason: 'Unexpected error happened, please try again' })
// generate the auth jwt token
const hour = 3600000
const maxAge = 30 * 24 * hour;
const jwt = await new jose.SignJWT({ pubKey: key })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime(maxAge)
//TODO: Set audience, issuer
.sign(Buffer.from(JWT_SECRET, 'utf-8'))
// associate the auth token with the hash in the db
console.log(hash);
await associateTokenToHash(hash, jwt);
// LnurlService.removeHash(LnurlService.createHash(k1)).catch();
// LnurlService.removeExpiredHashes().catch();
return res.status(200).json({ status: "OK" })
} catch (error) {
console.log(error);
return res.status(200).json({ status: 'ERROR', reason: 'Unexpected error happened, please try again' })
}
} }
} }

View File

@@ -24,6 +24,12 @@ functions:
- http: - http:
path: graphql path: graphql
method: get method: get
get-login-url:
handler: api/functions/get-login-url/get-login-url.handler
events:
- http:
path: get-login-url
method: get
login: login:
handler: api/functions/login/login.handler handler: api/functions/login/login.handler
events: events:

View File

@@ -1,12 +1,11 @@
import { useCallback, useEffect, useState } from "react" import { useCallback, useEffect, useState } from "react"
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { BsFillLightningChargeFill } from "react-icons/bs";
import { Grid } from "react-loader-spinner"; import { Grid } from "react-loader-spinner";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useMeQuery } from "src/graphql" import { useMeQuery } from "src/graphql"
import { CONSTS } from "src/utils"; import { CONSTS } from "src/utils";
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { IoQrCode, IoRocketOutline } from "react-icons/io5"; import { IoRocketOutline } from "react-icons/io5";
import Button from "src/Components/Button/Button"; import Button from "src/Components/Button/Button";
import { FiCopy } from "react-icons/fi"; import { FiCopy } from "react-icons/fi";
import useCopyToClipboard from "src/utils/hooks/useCopyToClipboard"; import useCopyToClipboard from "src/utils/hooks/useCopyToClipboard";
@@ -14,7 +13,7 @@ import useCopyToClipboard from "src/utils/hooks/useCopyToClipboard";
const fetchLnurlAuth = async () => { const fetchLnurlAuth = async () => {
const res = await fetch(CONSTS.apiEndpoint + '/login', { const res = await fetch(CONSTS.apiEndpoint + '/get-login-url', {
credentials: 'include' credentials: 'include'
}) })
const data = await res.json() const data = await res.json()
@@ -88,8 +87,6 @@ export default function LoginPage() {
const refetch = meQuery.refetch; const refetch = meQuery.refetch;
const startPolling = useCallback( const startPolling = useCallback(
() => { () => {
console.log('HEEY');
const interval = setInterval(() => { const interval = setInterval(() => {
fetch(CONSTS.apiEndpoint + '/is-logged-in', { fetch(CONSTS.apiEndpoint + '/is-logged-in', {
credentials: 'include' credentials: 'include'