admin, client Acts

This commit is contained in:
jusax23 2023-03-02 23:25:09 +01:00
parent a394dbe437
commit ed4b74362e
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
8 changed files with 313 additions and 22 deletions

View file

@ -1 +1,3 @@
export * from "./acts/login.js" export * from "./acts/login.js";
export * from "./acts/client.js"
export * from "./acts/admin.js"

171
src/api/acts/admin.ts Normal file
View file

@ -0,0 +1,171 @@
import { eq, insert, le, or, remove, select, update } from "dblang";
import { PERMISSIONS } from "../../server/permissions.js";
import { sha256 } from "../../sys/crypto.js";
import { accounts, db, signupOTA } from "../../sys/db.js";
import { get64, uts } from "../../sys/tools.js";
import { Client, STATE } from "../user.js";
export const getAccounts = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.SHOW_USERS_AND_LISTS,
data: {},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
let query = await select([
accounts.accID,
accounts.rights,
accounts.name,
accounts.viewable,
accounts.deleted,
accounts.maxRooms,
accounts.maxRoomSize,
accounts.maxUsersPerRoom
], accounts)
.query(db);
var out = query.map(d => {
let accID = d[accounts.accID];
let rights = d[accounts.rights];
let name = d[accounts.name];
let viewable = d[accounts.viewable];
let deleted = d[accounts.deleted];
let maxRooms = d[accounts.maxRooms];
let maxRoomSize = d[accounts.maxRoomSize];
let maxUsersPerRoom = d[accounts.maxUsersPerRoom];
if (accID != null && rights != null && name != null && viewable != null && deleted != null && maxRooms != null && maxRoomSize != null && maxUsersPerRoom != null) {
return { accID, rights, name, viewable, deleted, maxRooms, maxRoomSize, maxUsersPerRoom };
}
return null;
});
aws("ok", out.filter(d => d != null));
}
};
export const setPermissions = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.EDIT_RIGHTS,
data: {
accID: "number",
rights: "number"
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
let query = await update(accounts)
.set(accounts.rights, data.rights)
.where(eq(accounts.accID, data.accID))
.query(db);
if (query.affectedRows > 0) {
aws("ok", "");
} else {
client.suspect();
aws("error", "existence");
}
}
};
export const resetPassword = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.EDIT_USERS,
data: {
accID: "number",
accountKey: "string"
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
var salt = get64(16);
let req = await update(accounts)
.set(accounts.accountKey, sha256(salt + data.accountKey))
.set(accounts.accountKeySalt, salt)
.where(eq(accounts.accID, data.accID))
.query(db);
if (req.affectedRows > 0) {
aws("ok", "");
} else {
client.suspect();
aws("error", "existence");
}
}
};
export const setMaxValues = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.EDIT_USERS,
data: {
accID: "number",
maxRooms: "number",
maxRoomSize: "number",
maxUsersPerRoom: "number",
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
let req = await update(accounts)
.set(accounts.maxRooms, data.maxRooms)
.set(accounts.maxRoomSize, data.maxRoomSize)
.set(accounts.maxUsersPerRoom, data.maxUsersPerRoom)
.where(eq(accounts.accID, data.accID))
.query(db);
if (req.affectedRows > 0) {
aws("ok", "");
} else {
client.suspect();
aws("error", "existence");
}
}
};
export const getOTAs = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.MANAGE_OTA_TOKENS,
data: {},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
await remove(signupOTA)
.where(or(
eq(signupOTA.usesLeft, 0),
le(signupOTA.expires, uts())
))
.query(db);
let req = await select([
signupOTA.token,
signupOTA.expires,
signupOTA.usesLeft,
], signupOTA)
.query(db);
aws("ok", req.map(d => ({
token: d[signupOTA.token],
expires: d[signupOTA.expires],
usesLeft: d[signupOTA.usesLeft]
})));
}
}
export const addOTA = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.MANAGE_OTA_TOKENS,
data: {
token: "string-255",
expires: "number", //uts in sec.
usesLeft: "number"
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
try {
await insert(signupOTA.token, signupOTA.expires, signupOTA.usesLeft)
.add(data.token, data.expires, data. usesLeft)
.query(db);
} catch (error) {
await update(signupOTA)
.set(signupOTA.expires, data.expires)
.set(signupOTA.usesLeft, data.usesLeft)
.where(eq(signupOTA.token, data.token))
.query(db);
}
aws("ok", "");
}
}
export const deleteOTA = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.MANAGE_OTA_TOKENS,
data: {
token: "string"
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
await remove(signupOTA)
.where(eq(signupOTA.token, data.token))
.query(db);
aws("ok", "");
}
}

92
src/api/acts/client.ts Normal file
View file

@ -0,0 +1,92 @@
import { eq, select, update } from "dblang";
import { outbagURLshort } from "../../server/outbagURL.js";
import { PERMISSIONS } from "../../server/permissions.js";
import { oConf } from "../../sys/config.js";
import { sha256, sign } from "../../sys/crypto.js";
import { accounts, db } from "../../sys/db.js";
import { getSettings, SETTINGS } from "../../sys/settings.js";
import { get64 } from "../../sys/tools.js";
import { Client, STATE } from "../user.js";
export const deleteAccount = {
state: STATE.client,
right: 0,
data: {},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
client.state = STATE.no;
await update(accounts)
.set(accounts.deleted, 1)
.where(eq(accounts.accID, client.accID))
.query(db);
aws("ok", "");
}
};
export const createSignature = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API | PERMISSIONS.PROVIDE_CERT,
data: {
publicKey: "string"
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
const server = await outbagURLshort(oConf.get("System", "URL") + ":" + oConf.get("System", "PORTexposed"));
const tag = client.name + "@" + server + "-" + data.publicKey;
var signature = await sign(tag, await getSettings(SETTINGS.privateKey));
aws("ok", signature);
}
};
export const getMyAccount = {
state: STATE.client,
right: 0,
data: {},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
let query = await select([
accounts.rights,
accounts.name,
accounts.viewable,
accounts.maxRooms,
accounts.maxRoomSize,
accounts.maxUsersPerRoom,
], accounts)
.where(eq(accounts.accID, client.accID))
.query(db);
if (query.length > 0) {
let rights = query[0][accounts.rights];
let name = query[0][accounts.name];
let viewable = query[0][accounts.viewable];
let maxRooms = query[0][accounts.maxRooms];
let maxRoomSize = query[0][accounts.maxRoomSize];
let maxUsersPerRoom = query[0][accounts.maxUsersPerRoom];
if (rights != null && name != null && viewable != null && maxRooms != null && maxRoomSize != null && maxUsersPerRoom != null) {
aws("ok", { rights, name, viewable, maxRooms, maxRoomSize, maxUsersPerRoom });
return;
}
}
client.suspect();
aws("error", "existence");
}
};
export const changePassword = {
state: STATE.client,
right: PERMISSIONS.CAN_USE_API,
data: {
accountKey: "string"
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
var salt = get64(16);
let req = await update(accounts)
.set(accounts.accountKey, sha256(salt + data.accountKey))
.set(accounts.accountKeySalt, salt)
.where(eq(accounts.accID, client.accID))
.query(db);
if (req.affectedRows > 0) {
aws("ok", "");
} else {
client.suspect();
aws("error", "existence");
}
}
};

View file

@ -27,10 +27,10 @@ export const signup: Act = {
} }
let salt = get64(16); let salt = get64(16);
let req = await insert(accounts.name, accounts.rights, accounts.accountKey, accounts.accountKeySalt) let req = await insert(accounts.name, accounts.rights, accounts.accountKey, accounts.accountKeySalt)
.add(data.name, userNum == 0 ? PERMISSIONS.ALL : PERMISSIONS.DEFAULT, sha256(salt + data.accountKey)) .add(data.name, userNum == 0 ? PERMISSIONS.ALL : PERMISSIONS.DEFAULT, sha256(salt + data.accountKey), salt)
.query(db); .query(db);
if (req.affectedRows > 0) { if (req.affectedRows > 0) {
let accID = req.insertId; let accID = Number(req.insertId);
if (!isNaN(accID)) { if (!isNaN(accID)) {
aws("ok", ""); aws("ok", "");
client.state = STATE.client; client.state = STATE.client;
@ -69,10 +69,10 @@ export const signupOTA = {
} }
let salt = get64(16); let salt = get64(16);
let req = await insert(accounts.name, accounts.rights, accounts.accountKey, accounts.accountKeySalt) let req = await insert(accounts.name, accounts.rights, accounts.accountKey, accounts.accountKeySalt)
.add(data.name, PERMISSIONS.DEFAULT, sha256(salt + data.accountKey)) .add(data.name, PERMISSIONS.DEFAULT, sha256(salt + data.accountKey), salt)
.query(db); .query(db);
if (req.affectedRows > 0) { if (req.affectedRows > 0) {
let accID = req.insertId; let accID = Number(req.insertId);
if (!isNaN(accID)) { if (!isNaN(accID)) {
aws("ok", ""); aws("ok", "");
client.state = STATE.client; client.state = STATE.client;
@ -101,12 +101,12 @@ export const signin = {
eq(accounts.deleted, 0) eq(accounts.deleted, 0)
)) ))
.query(db); .query(db);
if (query.length == 0 || query[0].accountKey != sha256((query[0].accountKeySalt ?? '') + data.accountKey)) { if (query.length == 0 || query[0][accounts.accountKey] != sha256((query[0][accounts.accountKeySalt] ?? '') + data.accountKey)) {
client.suspect(); client.suspect();
aws("error", "auth"); aws("error", "auth");
return; return;
} }
var accID = query[0].ID; var accID = query[0][accounts.accID];
if (!isNaN(accID)) { if (!isNaN(accID)) {
aws("ok", ""); aws("ok", "");
client.state = STATE.client; client.state = STATE.client;

View file

@ -20,7 +20,7 @@ export const outbagURL = (url: string, prefix = "https") => new Promise((res, re
}) })
.catch(_ => { .catch(_ => {
if (uri.port == '') { if (uri.port == '') {
uri.port = DEFAULT_PORT+""; uri.port = DEFAULT_PORT + "";
outbagURL(uri.toString(), prefix) outbagURL(uri.toString(), prefix)
.then(url => res(url)) .then(url => res(url))
.catch(_ => rej()); .catch(_ => rej());
@ -29,6 +29,7 @@ export const outbagURL = (url: string, prefix = "https") => new Promise((res, re
} }
}); });
}); });
export const outbagURLshort = (url: string) => new Promise((res, rej) => { export const outbagURLshort = (url: string) => new Promise((res, rej) => {
let uri: URL; let uri: URL;
try { try {
@ -47,7 +48,7 @@ export const outbagURLshort = (url: string) => new Promise((res, rej) => {
}) })
.catch(_ => { .catch(_ => {
if (uri.port == '') { if (uri.port == '') {
uri.port = DEFAULT_PORT+""; uri.port = DEFAULT_PORT + "";
outbagURLshort(uri.toString()) outbagURLshort(uri.toString())
.then(url => res(url)) .then(url => res(url))
.catch(_ => rej()); .catch(_ => rej());

View file

@ -1,6 +1,3 @@
import { eq, select, update } from "dblang";
import { accounts, db } from "../sys/db.js";
export const PERMISSIONS = { export const PERMISSIONS = {
NONE: 0b0000000000000000, // equal to no account or blocked account NONE: 0b0000000000000000, // equal to no account or blocked account
@ -17,3 +14,13 @@ export const PERMISSIONS = {
EDIT_USERS: 0b1000000000000000, EDIT_USERS: 0b1000000000000000,
ALL: 0b1111111111111111, ALL: 0b1111111111111111,
}; };
export const ROOM_RIGHTS = { //when changing, look in main (db defaults)
ADD_ARTICLES: 0b0000001, //change or add articles
REMOVE_ARTICLES: 0b0000010,
LIST_GROUPS_ITEMS: 0b0000100, //edit room intern listGroups and listItems
CHANGE_META: 0b0001000,
OTA: 0b0010000, //edit otas
CHANGE_SETTINGS: 0b0100000,
MANAGE_MEMBERS: 0b1000000,
};

View file

@ -45,7 +45,7 @@ nMan.addShutdownTask(db.close, 3000, 10);
export const accounts = db.newTable("accounts"); export const accounts = db.newTable("accounts");
accounts.addAttributes({ accounts.addAttributes({
accID: { type: INT, primaryKey: true, autoIncrement: true }, accID: { type: INT, primaryKey: true, autoIncrement: true },
name: { type: VARCHAR(255), default: PERMISSIONS.DEFAULT }, name: { type: VARCHAR(100), default: PERMISSIONS.DEFAULT },
rights: { type: BIGINT, default: PERMISSIONS.DEFAULT }, rights: { type: BIGINT, default: PERMISSIONS.DEFAULT },

View file

@ -1,7 +1,8 @@
export const debug = (name: string, ...args: any[]) => { export const debug = (name: string, ...args: any[]) => {
if(!global.debug)return; if (!global.debug) return;
consorArgs(args);
console.log( console.log(
"\x1b[33m%s\x1b[0m"+ "\x1b[33m%s\x1b[0m" +
"\x1b[1m\x1b[32m%s\x1b[0m", "\x1b[1m\x1b[32m%s\x1b[0m",
(new Date()).toLocaleString(), (new Date()).toLocaleString(),
` [${name}]:`, ` [${name}]:`,
@ -10,8 +11,9 @@ export const debug = (name: string, ...args: any[]) => {
}; };
export const log = (name: string, ...args: string[]) => { export const log = (name: string, ...args: string[]) => {
consorArgs(args);
console.log( console.log(
"\x1b[33m%s\x1b[0m"+ "\x1b[33m%s\x1b[0m" +
"\x1b[1m\x1b[36m%s\x1b[0m", "\x1b[1m\x1b[36m%s\x1b[0m",
(new Date()).toLocaleString(), (new Date()).toLocaleString(),
` [${name}]:`, ` [${name}]:`,
@ -20,8 +22,9 @@ export const log = (name: string, ...args: string[]) => {
}; };
export const warn = (name: string, ...args: any[]) => { export const warn = (name: string, ...args: any[]) => {
consorArgs(args);
console.warn( console.warn(
"\x1b[33m%s\x1b[0m"+ "\x1b[33m%s\x1b[0m" +
"\x1b[1m\x1b[36m%s\x1b[0m", "\x1b[1m\x1b[36m%s\x1b[0m",
(new Date()).toLocaleString(), (new Date()).toLocaleString(),
` [${name}]:`, ` [${name}]:`,
@ -30,12 +33,27 @@ export const warn = (name: string, ...args: any[]) => {
}; };
export const error = (name: string, ...args: any[]) => { export const error = (name: string, ...args: any[]) => {
consorArgs(args);
console.error( console.error(
"\x1b[33m%s\x1b[0m"+ "\x1b[33m%s\x1b[0m" +
"\x1b[1m\x1b[41m%s\x1b[0m\x1b[41m", "\x1b[1m\x1b[41m%s\x1b[0m\x1b[41m",
(new Date()).toLocaleString()+" ", (new Date()).toLocaleString() + " ",
`[${name}]:`, `[${name}]:`,
...args, ...args,
"\x1b[0m" "\x1b[0m"
); );
}; };
const consorArgs = (args: any[]) => {
for (let i = 0; i < args.length; i++) {
const arg = args[i];
censorLogArg(arg);
}
}
const censorLogArg = (arg: any) => {
if (typeof arg != "object") return;
for (let key in arg) {
if (key == "accountKey") arg[key] = new Array(arg[key].length).fill("*").join("");
censorLogArg(arg[key]);
}
}