Support running without api access for dev

This commit is contained in:
pikiou 2022-01-30 02:43:16 +01:00
parent 65d9439308
commit aa76e33c54
5 changed files with 86 additions and 15 deletions

View File

@ -15,5 +15,5 @@ export default {
},
],
},
JWT_SECRET: "RblQqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!",
DEV_JWT_SECRET: "fakeqA6uF#msq2312bebf2FLFn4XzWQ6dttXSJwBX#?gL2JWf!",
}

View File

@ -16,7 +16,7 @@ import devServer from "./devServer"
import ssr from "./ssr"
import certbotRouter from "../routes/certbot"
import { secure } from "./secure"
import { hasSecret, secure } from "./secure"
import { javGameListGet } from "./gsheets/javGames"
import { preVolunteerAdd, preVolunteerCountGet } from "./gsheets/preVolunteers"
import { teamListGet } from "./gsheets/teams"
@ -34,6 +34,7 @@ import config from "../config"
import notificationsSubscribe from "./notificationsSubscribe"
import checkAccess from "./checkAccess"
import { hasGSheetsAccess } from "./gsheets/accessors"
import { addStatus, showStatusAt } from "./status"
checkAccess()
@ -122,6 +123,10 @@ if (validCertPath) {
const httpsOptions = _.mapValues(validCertPath, (pemPath: string) => fs.readFileSync(pemPath))
servers.push({ protocol: "https", server: https.createServer(httpsOptions, app) })
showStatusAt(6)
} else {
showStatusAt(5)
}
/**
@ -139,7 +144,7 @@ servers.forEach(({ protocol, server }) => {
function onError(error: any) {
if (error) {
console.error(chalk.red(`==> 😭 OMG!!! ${error}`))
addStatus("Server listening:", chalk.red(`==> 😭 OMG!!! ${error}`))
}
}
@ -150,13 +155,35 @@ function onError(error: any) {
function onListening(server: any) {
const addr = server.address()
const bind = typeof addr === "string" ? `pipe ${addr}` : `port ${addr.port}`
console.error(chalk.green(`\nServer listening on ${bind}`))
addStatus("Server listening:", chalk.green(` ${bind}`))
}
hasGSheetsAccess().then((hasApiAccess: boolean) => {
if (hasApiAccess) {
console.error(chalk.green(`Database: remote Google Sheet`))
addStatus("Database:", chalk.green(`✅ online from Google Sheet`))
} else {
console.error(chalk.green(`Database: local db`))
addStatus("Database:", chalk.blue(`🚧 offline, simulated from local db file`))
}
})
const hasSendGridApiAccess = !!process.env.SENDGRID_API_KEY
if (hasSendGridApiAccess) {
addStatus("Emailing:", chalk.green(`✅ online through SendGrid`))
} else {
addStatus("Emailing:", chalk.blue(`🚧 offline, simulated`))
}
const hasPushNotifAccess = !!process.env.FORCE_ORANGE_PUBLIC_VAPID_KEY
if (hasPushNotifAccess) {
addStatus("Push notif:", chalk.green(`✅ online with a Vapid key`))
} else {
addStatus("Push notif:", chalk.blue(`🚧 offline, simulated`))
}
hasSecret().then((has: boolean) => {
if (has) {
addStatus("JWT secret:", chalk.green(`✅ prod private one from file`))
} else {
addStatus("JWT secret:", chalk.blue(`🚧 dev public fake one from config`))
}
})

View File

@ -3,7 +3,8 @@ import webpush from "web-push"
const publicKey = process.env.FORCE_ORANGE_PUBLIC_VAPID_KEY
const privateKey = process.env.FORCE_ORANGE_PRIVATE_VAPID_KEY
if (publicKey && privateKey) {
const hasPushAccess = publicKey && privateKey
if (hasPushAccess) {
webpush.setVapidDetails("mailto: contact@parisestludique.fr", publicKey, privateKey)
}
@ -18,10 +19,19 @@ export default function notificationsSubscribe(
title: "Hello!",
body: "It works.",
})
webpush
.sendNotification(subscription, payload)
.then((result) => console.log(result))
.catch((e) => console.log(e.stack))
if (hasPushAccess) {
webpush
.sendNotification(subscription, payload)
.then((result) => console.log(result))
.catch((e) => console.log(e.stack))
} else {
console.error(
`Fake sending push notif to ${JSON.stringify(subscription)} of ${JSON.stringify(
payload
)})}`
)
}
response.status(200).json({ success: true })
}

View File

@ -1,6 +1,6 @@
import { NextFunction, Request, Response } from "express"
import path from "path"
import { promises as fs } from "fs"
import { constants, promises as fs } from "fs"
import { verify, sign } from "jsonwebtoken"
import config from "../config"
@ -8,6 +8,7 @@ import config from "../config"
type AuthorizedRequest = Request & { headers: { authorization: string } }
let cachedSecret: string
const SECRET_PATH = path.resolve(process.cwd(), "access/jwt_secret.json")
getSecret() // Necessary until we can make async express middleware
export function secure(request: AuthorizedRequest, response: Response, next: NextFunction): void {
@ -35,15 +36,28 @@ export function secure(request: AuthorizedRequest, response: Response, next: Nex
})
}
let hasSecretReturn: boolean | undefined
export async function hasSecret(): Promise<boolean> {
if (hasSecretReturn !== undefined) {
return hasSecretReturn
}
try {
// eslint-disable-next-line no-bitwise
await fs.access(SECRET_PATH, constants.R_OK | constants.W_OK)
hasSecretReturn = true
} catch {
hasSecretReturn = false
}
return hasSecretReturn
}
async function getSecret() {
if (!cachedSecret) {
const SECRET_PATH = path.resolve(process.cwd(), "access/jwt_secret.json")
try {
const secretContent = await fs.readFile(SECRET_PATH)
cachedSecret = secretContent && JSON.parse(secretContent.toString()).secret
} catch (e: any) {
cachedSecret = config.JWT_SECRET
cachedSecret = config.DEV_JWT_SECRET
}
}

20
src/server/status.ts Normal file
View File

@ -0,0 +1,20 @@
const messages: string[][] = []
let _messageCount = 0
export function addStatus(...messageParams: string[]): void {
messages.push(messageParams)
if (messages.length === _messageCount) {
showStatus()
} else if (messages.length > _messageCount) {
console.error(...messageParams)
}
}
function showStatus(): void {
console.error("")
messages.forEach((messageParams) => console.error(...messageParams))
}
export function showStatusAt(messageCount: number): void {
_messageCount = messageCount
}