don't allow users to just mount the prime db i guess for privacy reasons (may undo this someday)
This commit is contained in:
parent
464774ef4b
commit
5d7bcddcd1
4 changed files with 95 additions and 7 deletions
25
db.js
25
db.js
|
|
@ -7,6 +7,7 @@ const { Eta } = require("eta");
|
|||
const cheerio = require("cheerio");
|
||||
|
||||
const db = betterSqlite3("./dbs/0.sqlite");
|
||||
const PRIME_DB_ID = 0;
|
||||
|
||||
db.pragma("journal_mode = WAL");
|
||||
|
||||
|
|
@ -587,6 +588,7 @@ function getDbsForStructure(structureId) {
|
|||
FROM structure_dbs
|
||||
INNER JOIN dbs ON structure_dbs.db_id = dbs.id
|
||||
WHERE structure_dbs.structure_id = ?
|
||||
AND NOT (structure_dbs.db_id = ${PRIME_DB_ID} AND structure_dbs.structure_id != ${PRIME_DB_ID})
|
||||
ORDER BY structure_dbs.created_at, is_aliased ASC;
|
||||
`,
|
||||
)
|
||||
|
|
@ -607,11 +609,16 @@ function getDb(dbId) {
|
|||
function getDbForStructure(structureId, dbId) {
|
||||
return db
|
||||
.prepare(
|
||||
`SELECT *
|
||||
`SELECT
|
||||
dbs.*,
|
||||
structure_dbs.alias,
|
||||
structure_dbs.structure_id AS alias_struct_id,
|
||||
dbs.structure_id AS db_struct_id
|
||||
FROM structure_dbs
|
||||
INNER JOIN dbs ON structure_dbs.db_id = dbs.id
|
||||
WHERE structure_dbs.structure_id = ?
|
||||
AND structure_dbs.db_id = ?;
|
||||
AND structure_dbs.db_id = ?
|
||||
AND NOT (structure_dbs.db_id = ${PRIME_DB_ID} AND structure_dbs.structure_id != ${PRIME_DB_ID});
|
||||
`,
|
||||
)
|
||||
.get(structureId, dbId);
|
||||
|
|
@ -644,6 +651,9 @@ function createDb(structId, name) {
|
|||
}
|
||||
|
||||
function attachDb(structId, dbId, alias) {
|
||||
if (Number(dbId) === PRIME_DB_ID && Number(structId) !== PRIME_DB_ID) {
|
||||
throw new Error("prime db cannot be attached to other structures");
|
||||
}
|
||||
const insertStructureDbStmt = db.prepare(`
|
||||
INSERT INTO structure_dbs (db_id, structure_id, alias)
|
||||
VALUES (?, ?, ?)
|
||||
|
|
@ -698,10 +708,17 @@ function cloneStructure(
|
|||
).lastInsertRowid;
|
||||
|
||||
const dbIds = db
|
||||
.prepare(`SELECT db_id FROM structure_dbs WHERE structure_id = ?;`)
|
||||
.prepare(`SELECT db_id FROM structure_dbs WHERE structure_id = ? AND db_id != ${PRIME_DB_ID};`)
|
||||
.all(structId);
|
||||
|
||||
const toClone = new Set(cloneDbs);
|
||||
const requestedCloneDbs = Array.isArray(cloneDbs)
|
||||
? cloneDbs
|
||||
: cloneDbs
|
||||
? [cloneDbs]
|
||||
: [];
|
||||
const toClone = new Set(
|
||||
requestedCloneDbs.filter((dbId) => Number(dbId) !== PRIME_DB_ID),
|
||||
);
|
||||
const toAlias = new Set();
|
||||
|
||||
for (let { db_id } of dbIds) {
|
||||
|
|
|
|||
38
index.js
38
index.js
|
|
@ -12,11 +12,18 @@ const { match } = require("path-to-regexp");
|
|||
const bcrypt = require("bcrypt");
|
||||
const cheerio = require("cheerio");
|
||||
const webPush = require("web-push");
|
||||
const { randomUUID } = require("node:crypto");
|
||||
const app = express();
|
||||
const _expressWs = require("express-ws")(app);
|
||||
const bodyParser = require("body-parser");
|
||||
const model = require("./db");
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const SESSION_SECRET = process.env.SESSION_SECRET || randomUUID();
|
||||
if (!process.env.SESSION_SECRET) {
|
||||
console.warn(
|
||||
"SESSION_SECRET is not set; using an ephemeral secret and invalidating sessions on restart.",
|
||||
);
|
||||
}
|
||||
|
||||
const db = model.db;
|
||||
const wsRouter = express.Router();
|
||||
|
|
@ -62,7 +69,7 @@ app.use(fileUpload());
|
|||
app.use(
|
||||
session({
|
||||
store: new SQLiteStore({ client: db, expired: { clear: true } }),
|
||||
secret: "your secret key",
|
||||
secret: SESSION_SECRET,
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: { secure: false },
|
||||
|
|
@ -229,6 +236,26 @@ function currentUserFor(req) {
|
|||
}
|
||||
}
|
||||
|
||||
function dbForWorkshopRequest(req, res) {
|
||||
const appDb = model.getDbForStructure(
|
||||
req.params.structure_id,
|
||||
req.params.db_id,
|
||||
);
|
||||
if (!appDb) {
|
||||
res.status(404).send("Not found");
|
||||
return null;
|
||||
}
|
||||
const ownDb = String(appDb.db_struct_id) === String(req.params.structure_id);
|
||||
if (
|
||||
!ownDb &&
|
||||
!model.canAccessStructure(req.session.userId, appDb.db_struct_id)
|
||||
) {
|
||||
res.status(404).send("Not found");
|
||||
return null;
|
||||
}
|
||||
return appDb;
|
||||
}
|
||||
|
||||
function userIdFrom(value) {
|
||||
if (value == null) return null;
|
||||
if (typeof value === "object" && value.id != null) return Number(value.id);
|
||||
|
|
@ -925,6 +952,9 @@ app.post("/workshop/:structure_id/db", (req, res) => {
|
|||
});
|
||||
|
||||
app.post("/workshop/:structure_id/db/attach", (req, res) => {
|
||||
if (Number(req.body.db_id) === 0 && Number(req.params.structure_id) !== 0) {
|
||||
return res.status(400).send("prime db cannot be attached");
|
||||
}
|
||||
model.attachDb(req.params.structure_id, req.body.db_id, req.body.alias);
|
||||
const redirectUrl = `/workshop/${req.params.structure_id}/db/${req.body.db_id}`;
|
||||
return smartRedirect(req, res, redirectUrl);
|
||||
|
|
@ -993,7 +1023,8 @@ app.put("/workshop/:structure_id/route/:route_id", (req, res) => {
|
|||
app.put("/workshop/:structure_id/db/:db_id/library", (req, res) => {
|
||||
try {
|
||||
let dbId = req.params.db_id;
|
||||
let appDb = model.getDb(dbId);
|
||||
let appDb = dbForWorkshopRequest(req, res);
|
||||
if (!appDb) return;
|
||||
model.updateDb({ ...appDb, library: req.body.library });
|
||||
appDb = model.getDb(dbId);
|
||||
|
||||
|
|
@ -1018,7 +1049,8 @@ app.put("/workshop/:structure_id/db/:db_id/library", (req, res) => {
|
|||
app.post("/workshop/:structure_id/db/:db_id/repl", (req, res) => {
|
||||
try {
|
||||
let dbId = req.params.db_id;
|
||||
let appDb = model.getDb(dbId);
|
||||
let appDb = dbForWorkshopRequest(req, res);
|
||||
if (!appDb) return;
|
||||
let dbInstance = model.getDbInstance(dbId);
|
||||
let capturedOutput = [];
|
||||
let context = vm.createContext({
|
||||
|
|
|
|||
3
migrations/008_block_prime_mounts.sql
Normal file
3
migrations/008_block_prime_mounts.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
DELETE FROM structure_dbs
|
||||
WHERE db_id = 0
|
||||
AND structure_id != 0;
|
||||
|
|
@ -70,6 +70,42 @@ else
|
|||
echo "Dependencies unchanged; skipping npm install."
|
||||
fi
|
||||
|
||||
if [[ ! -f .env ]]; then
|
||||
install -m 600 /dev/null .env
|
||||
else
|
||||
chmod 600 .env || true
|
||||
fi
|
||||
|
||||
if ! grep -Eq '^SESSION_SECRET=.+$' .env; then
|
||||
SESSION_SECRET_VALUE="$(
|
||||
node -e 'process.stdout.write(require("crypto").randomBytes(48).toString("base64url"))'
|
||||
)"
|
||||
if grep -Eq '^SESSION_SECRET=' .env; then
|
||||
ENV_TMP="$(mktemp)"
|
||||
awk -v secret="$SESSION_SECRET_VALUE" '
|
||||
BEGIN { replaced = 0 }
|
||||
/^SESSION_SECRET=/ {
|
||||
if (!replaced) {
|
||||
print "SESSION_SECRET=" secret
|
||||
replaced = 1
|
||||
}
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
END {
|
||||
if (!replaced) print "SESSION_SECRET=" secret
|
||||
}
|
||||
' .env >"$ENV_TMP"
|
||||
cat "$ENV_TMP" >.env
|
||||
rm -f "$ENV_TMP"
|
||||
else
|
||||
printf '\nSESSION_SECRET=%s\n' "$SESSION_SECRET_VALUE" >>.env
|
||||
fi
|
||||
echo "Generated SESSION_SECRET in $APP_DIR/.env"
|
||||
else
|
||||
echo "SESSION_SECRET already present in $APP_DIR/.env"
|
||||
fi
|
||||
|
||||
PM2_TARGET=""
|
||||
if command -v pm2 >/dev/null 2>&1; then
|
||||
PM2_TARGET="$(pm2 jlist 2>/dev/null | APP_DIR="$APP_DIR" node -e '
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue