* WIP on mobile connections todo: register devices todo: data sync or connection * improve connection flow and registration add streaming from service TODO: user scoping * dev build mobile support * fix path * handle relative URLs * handle localhost access in product * add device de-register * sync styles * move UI to be out of the normal path since beta only * Add user scoping to mobile connection requests Remigrate DB for user associations Implement temp token registration to prevent unauthorized device registration requests cleanup middlewares
119 lines
2.9 KiB
JavaScript
119 lines
2.9 KiB
JavaScript
process.env.NODE_ENV === "development"
|
|
? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
|
|
: require("dotenv").config();
|
|
const JWT = require("jsonwebtoken");
|
|
const { User } = require("../../models/user");
|
|
const { jsonrepair } = require("jsonrepair");
|
|
const extract = require("extract-json-from-string");
|
|
|
|
function reqBody(request) {
|
|
return typeof request.body === "string"
|
|
? JSON.parse(request.body)
|
|
: request.body;
|
|
}
|
|
|
|
function queryParams(request) {
|
|
return request.query;
|
|
}
|
|
|
|
/**
|
|
* Creates a JWT with the given info and expiry
|
|
* @param {object} info - The info to include in the JWT
|
|
* @param {string} expiry - The expiry time for the JWT (default: 30 days)
|
|
* @returns {string} The JWT
|
|
*/
|
|
function makeJWT(info = {}, expiry = "30d") {
|
|
if (!process.env.JWT_SECRET)
|
|
throw new Error("Cannot create JWT as JWT_SECRET is unset.");
|
|
return JWT.sign(info, process.env.JWT_SECRET, { expiresIn: expiry });
|
|
}
|
|
|
|
// Note: Only valid for finding users in multi-user mode
|
|
// as single-user mode with password is not a "user"
|
|
async function userFromSession(request, response = null) {
|
|
if (!!response && !!response.locals?.user) {
|
|
return response.locals.user;
|
|
}
|
|
|
|
const auth = request.header("Authorization");
|
|
const token = auth ? auth.split(" ")[1] : null;
|
|
|
|
if (!token) {
|
|
return null;
|
|
}
|
|
|
|
const valid = decodeJWT(token);
|
|
if (!valid || !valid.id) {
|
|
return null;
|
|
}
|
|
|
|
const user = await User.get({ id: valid.id });
|
|
return user;
|
|
}
|
|
|
|
function decodeJWT(jwtToken) {
|
|
try {
|
|
return JWT.verify(jwtToken, process.env.JWT_SECRET);
|
|
} catch {}
|
|
return { p: null, id: null, username: null };
|
|
}
|
|
|
|
function multiUserMode(response) {
|
|
return response?.locals?.multiUserMode;
|
|
}
|
|
|
|
function parseAuthHeader(headerValue = null, apiKey = null) {
|
|
if (headerValue === null || apiKey === null) return {};
|
|
if (headerValue === "Authorization")
|
|
return { Authorization: `Bearer ${apiKey}` };
|
|
return { [headerValue]: apiKey };
|
|
}
|
|
|
|
function safeJsonParse(jsonString, fallback = null) {
|
|
if (jsonString === null) return fallback;
|
|
|
|
try {
|
|
return JSON.parse(jsonString);
|
|
} catch {}
|
|
|
|
if (jsonString?.startsWith("[") || jsonString?.startsWith("{")) {
|
|
try {
|
|
const repairedJson = jsonrepair(jsonString);
|
|
return JSON.parse(repairedJson);
|
|
} catch {}
|
|
}
|
|
|
|
try {
|
|
return extract(jsonString)?.[0] || fallback;
|
|
} catch {}
|
|
|
|
return fallback;
|
|
}
|
|
|
|
function isValidUrl(urlString = "") {
|
|
try {
|
|
const url = new URL(urlString);
|
|
if (!["http:", "https:"].includes(url.protocol)) return false;
|
|
return true;
|
|
} catch (e) {}
|
|
return false;
|
|
}
|
|
|
|
function toValidNumber(number = null, fallback = null) {
|
|
if (isNaN(Number(number))) return fallback;
|
|
return Number(number);
|
|
}
|
|
|
|
module.exports = {
|
|
reqBody,
|
|
multiUserMode,
|
|
queryParams,
|
|
makeJWT,
|
|
decodeJWT,
|
|
userFromSession,
|
|
parseAuthHeader,
|
|
safeJsonParse,
|
|
isValidUrl,
|
|
toValidNumber,
|
|
};
|