refactor: auth funcs

This commit is contained in:
MTG2000
2022-06-02 13:22:06 +03:00
parent ffbc839806
commit 58a9e1edd1
4 changed files with 86 additions and 66 deletions

View File

@@ -20,52 +20,61 @@ async function login(tag, k1, sig, key) {
return { status: 'ERROR', reason: 'Not a login request' }
}
const result = LnurlService.verifySig(sig, k1, key)
if (!result) {
try {
await LnurlService.verifySig(sig, k1, key)
} catch (error) {
return { status: 'ERROR', reason: 'Invalid Signature' }
}
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`
}
try {
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`
}
})
}
// Set cookies on the user's headers
const hour = 3600000
const maxAge = 30 * 24 * hour
const jwtSecret = CONSTS.JWT_SECRET;
LnurlService.removeHash(LnurlService.createHash(k1)).catch();
LnurlService.removeExpiredHashes().catch();
const jwt = await new jose.SignJWT({ pubKey: key })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime(maxAge)
//TODO: Set audience, issuer
.sign(Buffer.from(jwtSecret, 'utf-8'))
const authCookie = cookie.serialize('Authorization', `Bearer ${jwt}`, {
secure: true,
httpOnly: true,
path: '/',
maxAge: maxAge,
})
}
return {
status: 'OK',
'headers': {
'Set-Cookie': authCookie,
'Cache-Control': 'no-cache',
},
}
} catch (error) {
return { status: 'ERROR', reason: 'Unexpected error happened, please try again' }
// Set cookies on the user's headers
const hour = 3600000
const maxAge = 30 * 24 * hour
const jwtSecret = CONSTS.JWT_SECRET;
const jwt = await new jose.SignJWT({ pubKey: key })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime(maxAge)
//TODO: Set audience, issuer
.sign(Buffer.from(jwtSecret, 'utf-8'))
const authCookie = cookie.serialize('Authorization', `Bearer ${jwt}`, {
secure: true,
httpOnly: true,
path: '/',
maxAge: maxAge,
})
return {
status: 'OK',
'headers': {
'Set-Cookie': authCookie,
'Cache-Control': 'no-cache',
},
}
}

View File

@@ -29,7 +29,7 @@ function isHashUsed(hash) {
}
function addHash(hash) {
prisma.generatedK1.create({
return prisma.generatedK1.create({
data: {
value: hash,
}
@@ -37,7 +37,7 @@ function addHash(hash) {
}
function removeHash(hash) {
prisma.generatedK1.delete({
return prisma.generatedK1.delete({
where: {
value: hash,
}
@@ -48,7 +48,7 @@ function removeExpiredHashes() {
const now = new Date();
const lastHourDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours() - 1, now.getMinutes());
prisma.generatedK1.deleteMany({
return prisma.generatedK1.deleteMany({
where: {
createdAt: {
lt: lastHourDate
@@ -60,7 +60,7 @@ function removeExpiredHashes() {
async function generateAuthUrl() {
const hostname = CONSTS.LNURL_AUTH_HOST;
const secret = await generateSecret()
addHash(createHash(secret))
await addHash(createHash(secret))
const url = `${hostname}?tag=login&k1=${secret}`
return {
url,
@@ -69,12 +69,15 @@ async function generateAuthUrl() {
}
}
function verifySig(sig, k1, key) {
async function verifySig(sig, k1, key) {
if (!lnurl.verifyAuthorizationSignature(sig, k1, key)) {
const message = 'Signature verification failed'
throw new Error(message)
}
const hash = createHash(k1)
const hashExist = await isHashUsed(hash);
if (!hashExist)
throw new Error('Provided k1 is not issued by server')
return { key, hash }
}
@@ -94,5 +97,6 @@ module.exports = {
generateAuthUrl: generateAuthUrl,
verifySig: verifySig,
removeHash: removeHash,
createHash: createHash,
removeExpiredHashes: removeExpiredHashes
}

View File

@@ -4,25 +4,25 @@ const cookie = require('cookie')
const jose = require('jose');
const { CONSTS } = require('../utils');
const extractKey = async (cookieHeader) => {
const cookies = cookie.parse(cookieHeader ?? '');
const authToken = cookies.Authorization;
if (authToken) {
const token = authToken.split(' ')[1];
const { payload } = await jose.jwtVerify(token, Buffer.from(CONSTS.JWT_SECRET), {
algorithms: ['HS256'],
})
return payload.pubKey
}
return null;
}
const server = new ApolloServer({
schema,
context: async ({ event }) => {
const cookies = cookie.parse(event.headers.Cookie ?? '');
const authToken = cookies.Authorization;
if (authToken) {
const token = authToken.split(' ')[1];
const { payload } = await jose.jwtVerify(token, Buffer.from(CONSTS.JWT_SECRET), {
algorithms: ['HS256'],
})
return { userPubKey: payload.pubKey }
}
return {
};
const userPubKey = await extractKey(event.headers.Cookie)
return { userPubKey, }
},
});

View File

@@ -1,3 +1,4 @@
import { useMountEffect } from "@react-hookz/web";
import { useEffect, useState } from "react"
import { BsFillLightningChargeFill } from "react-icons/bs";
import { Grid } from "react-loader-spinner";
@@ -5,6 +6,14 @@ import { useNavigate } from "react-router-dom";
import { useMeQuery } from "src/graphql"
const getLnurlAuth = async () => {
const res = await fetch(process.env.REACT_APP_AUTH_END_POINT! + '/login')
const data = await res.json()
return data;
}
export default function LoginPage() {
const [loadingLnurl, setLoadingLnurl] = useState(true)
const [lnurlAuth, setLnurlAuth] = useState("");
@@ -27,14 +36,12 @@ export default function LoginPage() {
useEffect(() => {
(async () => {
const res = await fetch(process.env.REACT_APP_AUTH_END_POINT! + '/login')
const data = await res.json()
useMountEffect(() => {
getLnurlAuth().then(data => {
setLoadingLnurl(false);
setLnurlAuth(data.encoded)
})();
}, [])
})
})
@@ -63,7 +70,7 @@ export default function LoginPage() {
<p className="text-body1 font-bolder text-center">
Login
</p>
<p className="text-gray-600 text-body-4">
<p className="text-gray-600 text-body4 text-center">
Zero credentials authentication.
<br />
All you need is a connected <a href='https://getalby.com'