mirror of
https://github.com/aljazceru/landscape-template.git
synced 2025-12-18 14:54:23 +01:00
refactor: migrate to jwt sessions instead of store sessions
This commit is contained in:
@@ -27,11 +27,10 @@ function isHashUsed(hash) {
|
||||
return prisma.generatedK1.findFirst({ where: { value: hash } })
|
||||
}
|
||||
|
||||
function addHash(hash, sid) {
|
||||
function addHash(hash) {
|
||||
return prisma.generatedK1.create({
|
||||
data: {
|
||||
value: hash,
|
||||
sid,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -46,7 +45,7 @@ function removeHash(hash) {
|
||||
|
||||
function removeExpiredHashes() {
|
||||
const now = new Date();
|
||||
const lastHourDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours() - 1, now.getMinutes());
|
||||
const lastHourDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes() - 10);
|
||||
|
||||
return prisma.generatedK1.deleteMany({
|
||||
where: {
|
||||
@@ -57,20 +56,21 @@ function removeExpiredHashes() {
|
||||
})
|
||||
}
|
||||
|
||||
async function generateAuthUrl(sid) {
|
||||
async function generateAuthUrl() {
|
||||
const hostname = CONSTS.LNURL_AUTH_HOST;
|
||||
const secret = await generateSecret()
|
||||
await addHash(createHash(secret), sid)
|
||||
const secret = await generateSecret();
|
||||
const hash = createHash(secret);
|
||||
await addHash(hash)
|
||||
const url = `${hostname}?tag=login&k1=${secret}`
|
||||
return {
|
||||
url,
|
||||
encoded: lnurl.encode(url).toUpperCase(),
|
||||
secret,
|
||||
secretHash: hash,
|
||||
}
|
||||
}
|
||||
|
||||
async function getSidByK1(k1) {
|
||||
const hash = createHash(k1)
|
||||
async function getAuthTokenByHash(hash) {
|
||||
const data = await prisma.generatedK1.findFirst({
|
||||
where: {
|
||||
value: hash,
|
||||
@@ -79,6 +79,17 @@ async function getSidByK1(k1) {
|
||||
return data.sid;
|
||||
}
|
||||
|
||||
function associateTokenToHash(hash, token) {
|
||||
return prisma.generatedK1.update({
|
||||
where: {
|
||||
value: hash
|
||||
},
|
||||
data: {
|
||||
sid: token
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function verifySig(sig, k1, key) {
|
||||
if (!lnurl.verifyAuthorizationSignature(sig, k1, key)) {
|
||||
const message = 'Signature verification failed'
|
||||
@@ -105,141 +116,12 @@ function createHash(data) {
|
||||
|
||||
|
||||
|
||||
|
||||
// function setupAuthMiddelwares(app) {
|
||||
// app.use(session({
|
||||
// secret: "12345",
|
||||
// resave: false,
|
||||
// saveUninitialized: true,
|
||||
// store: new SQLiteStore()
|
||||
// }));
|
||||
|
||||
// passport.use(
|
||||
// new lnurlAuth.Strategy(function (linkingPublicKey, done) {
|
||||
// const user = { id: linkingPublicKey };
|
||||
// console.log("Strategy Function");
|
||||
// console.log(user);
|
||||
// // let user = map.user.get(linkingPublicKey);
|
||||
// // if (!user) {
|
||||
// // user = { id: linkingPublicKey };
|
||||
// // map.user.set(linkingPublicKey, user);
|
||||
// // }
|
||||
// done(null, user);
|
||||
// })
|
||||
// );
|
||||
|
||||
// app.use(passport.initialize());
|
||||
// app.use(passport.session());
|
||||
// app.use(passport.authenticate("lnurl-auth"));
|
||||
// passport.serializeUser(function (user, done) {
|
||||
// done(null, user.id);
|
||||
// });
|
||||
|
||||
// passport.deserializeUser(function (id, done) {
|
||||
|
||||
// // done(null, map.user.get(id) || null);
|
||||
// done(null, id || null);
|
||||
// });
|
||||
// return app;
|
||||
// /*
|
||||
// app.get(
|
||||
// "/do-login",
|
||||
// function (req, res, next) {
|
||||
// next();
|
||||
// },
|
||||
// async function (req, res) {
|
||||
|
||||
|
||||
// if (req.query.k1 || req.query.key || req.query.sig) {
|
||||
// // Check signature against provided linking public key.
|
||||
// // This request could originate from a mobile app (ie. not their browser).
|
||||
// let session;
|
||||
// assert.ok(
|
||||
// req.query.k1,
|
||||
// new HttpError('Missing required parameter: "k1"', 400)
|
||||
// );
|
||||
// assert.ok(
|
||||
// req.query.sig,
|
||||
// new HttpError('Missing required parameter: "sig"', 400)
|
||||
// );
|
||||
// assert.ok(
|
||||
// req.query.key,
|
||||
// new HttpError('Missing required parameter: "key"', 400)
|
||||
// );
|
||||
// session = map.session.get(req.query.k1);
|
||||
// assert.ok(
|
||||
// session,
|
||||
// new HttpError("Secret does not match any known session", 400)
|
||||
// );
|
||||
// const { k1, sig, key } = req.query;
|
||||
// assert.ok(
|
||||
// verifyAuthorizationSignature(sig, k1, key),
|
||||
// new HttpError("Invalid signature", 400)
|
||||
// );
|
||||
// session.lnurlAuth = session.lnurlAuth || {};
|
||||
// session.lnurlAuth.linkingPublicKey = req.query.key;
|
||||
|
||||
|
||||
// const result = await session.save();
|
||||
// console.log(result);
|
||||
// res.status(200).json({ status: "OK" });
|
||||
// }
|
||||
|
||||
// req.session = req.session || {};
|
||||
// req.session.lnurlAuth = req.session.lnurlAuth || {};
|
||||
// let k1 = req.session.lnurlAuth.k1 || null;
|
||||
// if (!k1) {
|
||||
// k1 = req.session.lnurlAuth.k1 = generateSecret(32, "hex");
|
||||
// map.session.set(k1, req.session);
|
||||
// }
|
||||
|
||||
// const callbackUrl =
|
||||
// "https://" +
|
||||
// `${req.get("host")}/do-login?${querystring.stringify({
|
||||
// k1,
|
||||
// tag: "login",
|
||||
// })}`;
|
||||
|
||||
// const encoded = lnurl.encode(callbackUrl).toUpperCase();
|
||||
// const qrCode = await qrcode.toDataURL(encoded);
|
||||
// return res.json({
|
||||
// lnurl: encoded,
|
||||
// qrCode: qrCode,
|
||||
// });
|
||||
// }
|
||||
// );
|
||||
// */
|
||||
|
||||
// // app.get("/logout", function (req, res, next) {
|
||||
// // if (req.user) {
|
||||
// // req.session.destroy();
|
||||
// // return res.redirect("/");
|
||||
// // }
|
||||
// // next();
|
||||
// // });
|
||||
|
||||
// // app.get("/me", function (req, res, next) {
|
||||
// // res.json({ user: req.user ? req.user : null });
|
||||
|
||||
// // next();
|
||||
// // });
|
||||
|
||||
// // app.get("/profile", function (req, res, next) {
|
||||
// // if (!req.user) {
|
||||
// // return res.redirect("/login");
|
||||
// // }
|
||||
|
||||
// // res.render("profile", { user: req.user });
|
||||
|
||||
// // next();
|
||||
// // });
|
||||
// }
|
||||
|
||||
module.exports = {
|
||||
generateAuthUrl: generateAuthUrl,
|
||||
verifySig: verifySig,
|
||||
removeHash: removeHash,
|
||||
createHash: createHash,
|
||||
removeExpiredHashes: removeExpiredHashes,
|
||||
getSidByK1: getSidByK1
|
||||
getAuthTokenByHash: getAuthTokenByHash,
|
||||
associateTokenToHash: associateTokenToHash
|
||||
}
|
||||
@@ -1,12 +1,26 @@
|
||||
const { ApolloServer } = require("apollo-server-lambda");
|
||||
const schema = require('./schema')
|
||||
const cookie = require('cookie')
|
||||
const jose = require('jose');
|
||||
const { createExpressApp } = require("../../modules");
|
||||
const { JWT_SECRET } = require("../../utils/consts");
|
||||
|
||||
const extractKey = async (cookieHeader) => {
|
||||
const cookies = cookie.parse(cookieHeader ?? '');
|
||||
const token = cookies.Authorization;
|
||||
if (token) {
|
||||
const { payload } = await jose.jwtVerify(token, Buffer.from(JWT_SECRET), {
|
||||
algorithms: ['HS256'],
|
||||
})
|
||||
return payload.pubKey
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const server = new ApolloServer({
|
||||
schema,
|
||||
context: async ({ event, context, express }) => {
|
||||
const userPubKey = express.req.user?.id;
|
||||
context: async ({ event }) => {
|
||||
const userPubKey = await extractKey(event.headers.cookie ?? event.headers.Cookie)
|
||||
return { userPubKey }
|
||||
},
|
||||
});
|
||||
@@ -19,11 +33,6 @@ const apolloHandler = server.createHandler({
|
||||
origin: ['http://localhost:3000', 'https://studio.apollographql.com'],
|
||||
credentials: true,
|
||||
}
|
||||
},
|
||||
expressAppFromMiddleware(middleware) {
|
||||
const app = createExpressApp();
|
||||
app.use(middleware)
|
||||
return app;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
87
api/functions/is-logged-in/is-logged-in.js
Normal file
87
api/functions/is-logged-in/is-logged-in.js
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
const serverless = require('serverless-http');
|
||||
const { getAuthTokenByHash } = require('../../auth/services/lnurl.service');
|
||||
const { createExpressApp } = require('../../modules');
|
||||
const express = require('express');
|
||||
const jose = require('jose');
|
||||
const { JWT_SECRET } = require('../../utils/consts');
|
||||
const lnurlService = require('../../auth/services/lnurl.service');
|
||||
|
||||
|
||||
const isLoggedInHandler = async (req, res) => {
|
||||
// console.log(req.cookies);
|
||||
try {
|
||||
const login_session = req.cookies?.login_session;
|
||||
// console.log(login_session);
|
||||
if (login_session) {
|
||||
|
||||
const { payload } = await jose.jwtVerify(login_session, Buffer.from(JWT_SECRET), {
|
||||
algorithms: ['HS256'],
|
||||
});
|
||||
const hash = payload.hash;
|
||||
const token = await getAuthTokenByHash(hash);
|
||||
|
||||
|
||||
lnurlService.removeHash(hash).catch();
|
||||
lnurlService.removeExpiredHashes().catch();
|
||||
|
||||
res
|
||||
.status(200)
|
||||
.cookie('Authorization', token, {
|
||||
maxAge: 3600000 * 24 * 30,
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
})
|
||||
.clearCookie('login_session', {
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
})
|
||||
.json({
|
||||
logged_in: true
|
||||
});
|
||||
// console.log(payload);
|
||||
} else {
|
||||
|
||||
res.json({
|
||||
me: null
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.json({
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
express.Router().get('id', (req, res) => {
|
||||
res.clearCookie('Au')
|
||||
})
|
||||
|
||||
|
||||
let app;
|
||||
|
||||
if (process.env.LOCAL) {
|
||||
app = createExpressApp()
|
||||
app.get('/is-logged-in', isLoggedInHandler);
|
||||
}
|
||||
else {
|
||||
const router = express.Router();
|
||||
router.get('/is-logged-in', isLoggedInHandler)
|
||||
app = createExpressApp(router)
|
||||
}
|
||||
|
||||
|
||||
const handler = serverless(app);
|
||||
exports.handler = async (event, context) => {
|
||||
return await handler(event, context);
|
||||
};
|
||||
@@ -2,18 +2,44 @@
|
||||
const { prisma } = require('../../prisma');
|
||||
const LnurlService = require('../../auth/services/lnurl.service')
|
||||
const serverless = require('serverless-http');
|
||||
const { getSidByK1 } = require('../../auth/services/lnurl.service');
|
||||
const { getAuthTokenByHash, createHash, associateTokenToHash } = require('../../auth/services/lnurl.service');
|
||||
const { sessionsStore, createExpressApp } = require('../../modules');
|
||||
const express = require('express');
|
||||
const jose = require('jose');
|
||||
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,
|
||||
})
|
||||
})
|
||||
|
||||
const loginHandler = async (req, res) => {
|
||||
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 data = await LnurlService.generateAuthUrl(req.sessionID);
|
||||
return res.status(200).json(data);
|
||||
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,
|
||||
})
|
||||
.json(data);
|
||||
}
|
||||
else {
|
||||
if (tag !== 'login')
|
||||
@@ -41,26 +67,26 @@ const loginHandler = async (req, res) => {
|
||||
})
|
||||
}
|
||||
|
||||
// calc the hash of k1
|
||||
const hash = createHash(k1);
|
||||
|
||||
// Update the session with the secret
|
||||
const sid = await getSidByK1(k1);
|
||||
const d = await new Promise((res, rej) => {
|
||||
sessionsStore.get(sid, (err, d) => {
|
||||
if (err) rej(err);
|
||||
res(d)
|
||||
})
|
||||
});
|
||||
// console.log(d);
|
||||
await new Promise((res, rej) => {
|
||||
sessionsStore.set(sid, { ...d, lnurlAuth: { linkingPublicKey: key } }, (err) => {
|
||||
if (err) rej(err);
|
||||
res()
|
||||
})
|
||||
});
|
||||
// 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'))
|
||||
|
||||
LnurlService.removeHash(LnurlService.createHash(k1)).catch();
|
||||
LnurlService.removeExpiredHashes().catch();
|
||||
// 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" })
|
||||
|
||||
|
||||
@@ -3,11 +3,15 @@ const { createExpressApp } = require('../../modules');
|
||||
const express = require('express');
|
||||
|
||||
const logoutHandler = (req, res, next) => {
|
||||
if (req.user) {
|
||||
req.session.destroy();
|
||||
return res.redirect("/");
|
||||
}
|
||||
next();
|
||||
|
||||
res
|
||||
.clearCookie('Authorization', {
|
||||
secure: true,
|
||||
httpOnly: true,
|
||||
})
|
||||
.redirect("/")
|
||||
.end()
|
||||
|
||||
};
|
||||
|
||||
let app;
|
||||
|
||||
@@ -1,52 +1,19 @@
|
||||
|
||||
const express = require('express');
|
||||
const session = require("express-session");
|
||||
const passport = require("passport");
|
||||
const lnurlAuth = require("passport-lnurl-auth");
|
||||
var cors = require('cors');
|
||||
const { SESSION_SECRET } = require('../utils/consts');
|
||||
const createGlobalModule = require('../utils/createGlobalModule');
|
||||
const sessionsStore = require('./sessions-store');
|
||||
const cookieParser = require('cookie-parser');
|
||||
|
||||
const createExpressApp = (router) => {
|
||||
|
||||
const app = express();
|
||||
const routerBasePath = process.env.LOCAL ? `/dev` : `/.netlify/functions`
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(cors({
|
||||
origin: ['http://localhost:3000', 'https://studio.apollographql.com'],
|
||||
credentials: true,
|
||||
}))
|
||||
|
||||
app.use(session({
|
||||
secret: SESSION_SECRET,
|
||||
resave: false,
|
||||
store: sessionsStore,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
passport.use(new lnurlAuth.Strategy(function (linkingPublicKey, done) {
|
||||
// The user has successfully authenticated using lnurl-auth.
|
||||
// The linked public key is provided here.
|
||||
// You can use this as a unique reference for the user similar to a username or email address.
|
||||
const user = { id: linkingPublicKey };
|
||||
done(null, user);
|
||||
}));
|
||||
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
app.use(passport.authenticate("lnurl-auth"));
|
||||
passport.serializeUser(function (user, done) {
|
||||
done(null, user?.id);
|
||||
});
|
||||
passport.deserializeUser(function (id, done) {
|
||||
done(null, { id } || null);
|
||||
});
|
||||
|
||||
if (router)
|
||||
app.use(routerBasePath, router);
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
const createExpressApp = require("./express-app");
|
||||
const sessionsStore = require("./sessions-store");
|
||||
|
||||
|
||||
module.exports = {
|
||||
createExpressApp,
|
||||
sessionsStore,
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
const createGlobalModule = require("../utils/createGlobalModule");
|
||||
|
||||
let sessionsStore;
|
||||
|
||||
const createSessionStore = () => {
|
||||
const session = require("express-session");
|
||||
var Store = require('connect-pg-simple')(session);
|
||||
console.log("New Sessions Store");
|
||||
return new Store({
|
||||
createTableIfMissing: true,
|
||||
tableName: "user_sessions",
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
sessionsStore = createGlobalModule('sessions-store', createSessionStore);
|
||||
|
||||
module.exports = sessionsStore;
|
||||
6
api/utils/generateId.js
Normal file
6
api/utils/generateId.js
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
const generateId = () => crypto.randomUUID({});
|
||||
|
||||
module.exports = generateId;
|
||||
37
package-lock.json
generated
37
package-lock.json
generated
@@ -35,6 +35,7 @@
|
||||
"connect-pg-simple": "^7.0.0",
|
||||
"connect-sqlite3": "^0.9.13",
|
||||
"cookie": "^0.5.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "^2.8.5",
|
||||
"crypto": "^1.0.1",
|
||||
"dayjs": "^1.11.1",
|
||||
@@ -19814,6 +19815,26 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser": {
|
||||
"version": "1.4.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
|
||||
"integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
|
||||
"dependencies": {
|
||||
"cookie": "0.4.1",
|
||||
"cookie-signature": "1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser/node_modules/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
@@ -82812,6 +82833,22 @@
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
|
||||
},
|
||||
"cookie-parser": {
|
||||
"version": "1.4.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
|
||||
"integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
|
||||
"requires": {
|
||||
"cookie": "0.4.1",
|
||||
"cookie-signature": "1.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"connect-pg-simple": "^7.0.0",
|
||||
"connect-sqlite3": "^0.9.13",
|
||||
"cookie": "^0.5.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "^2.8.5",
|
||||
"crypto": "^1.0.1",
|
||||
"dayjs": "^1.11.1",
|
||||
|
||||
@@ -27,18 +27,18 @@ functions:
|
||||
login:
|
||||
handler: api/functions/login/login.handler
|
||||
events:
|
||||
- http:
|
||||
path: login
|
||||
method: post
|
||||
- http:
|
||||
path: login
|
||||
method: get
|
||||
logout:
|
||||
handler: api/functions/logout/logout.handler
|
||||
events:
|
||||
- http:
|
||||
path: logout
|
||||
method: post
|
||||
- http:
|
||||
path: logout
|
||||
method: get
|
||||
is-logged-in:
|
||||
handler: api/functions/is-logged-in/is-logged-in.handler
|
||||
events:
|
||||
- http:
|
||||
path: is-logged-in
|
||||
method: get
|
||||
|
||||
14
src/App.tsx
14
src/App.tsx
@@ -9,6 +9,7 @@ import LoadingPage from "./Components/LoadingPage/LoadingPage";
|
||||
import { useMeQuery } from "./graphql";
|
||||
import { setUser } from "./redux/features/user.slice";
|
||||
import ProtectedRoute from "./Components/ProtectedRoute/ProtectedRoute";
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
// Pages
|
||||
const FeedPage = React.lazy(() => import("./features/Posts/pages/FeedPage/FeedPage"))
|
||||
@@ -62,6 +63,19 @@ function App() {
|
||||
|
||||
|
||||
return <div id="app" className='w-full'>
|
||||
<Helmet>
|
||||
<title >makers.bolt.fun</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="A lightning app directory made for and by the bitcoin community."
|
||||
|
||||
/>
|
||||
<meta
|
||||
property="og:title"
|
||||
content="makers.bolt.fun"
|
||||
|
||||
/>
|
||||
</Helmet>
|
||||
<Navbar />
|
||||
<Suspense fallback={<LoadingPage />}>
|
||||
<Routes>
|
||||
|
||||
@@ -57,7 +57,18 @@ export default function LoginPage() {
|
||||
}, [])
|
||||
|
||||
const startPolling = () => {
|
||||
meQuery.startPolling(3000)
|
||||
// meQuery.startPolling(3000)
|
||||
const interval = setInterval(() => {
|
||||
fetch(CONSTS.apiEndpoint + '/is-logged-in', {
|
||||
credentials: 'include'
|
||||
}).then(data => data.json())
|
||||
.then(data => {
|
||||
if (data.logged_in) {
|
||||
clearInterval(interval)
|
||||
meQuery.refetch();
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user