This commit is contained in:
2024-10-29 19:49:24 +02:00
commit 11eb888b9c
42 changed files with 7877 additions and 0 deletions
+186
View File
@@ -0,0 +1,186 @@
import { ObjectId, MongoClient } from 'mongodb';
let db;
let dbo;
class Db {
name = 'db';
init(app){
this.app = app;
}
async start(app){
db = await MongoClient.connect(app.config.db.url, {maxPoolSize: 256});
try {
dbo = db.db(app.config.db.name);
this.instance = dbo;
for (let c of ['users', 'user_sessions', 'history', 'log', 'assets']){
try {
await dbo.createCollection(c);
}catch(err){}
}
}finally{
}
}
async create(collection, value){
try {
delete value._id;
return await dbo.collection(collection).insertOne(value);
}finally{
}
}
async get(collection, key, projection){
try {
let res = await dbo.collection(collection).findOne(key, projection ? {projection} : undefined)
return res;
}finally{
}
}
async list(collection, query){
try {
let cursor = dbo.collection(collection).find(query.query, query.project ? {projection: query.project} : undefined);
query.sort && cursor.sort(query.sort);
query.skip && cursor.skip(query.skip);
query.limit && cursor.limit(query.limit);
let count = await dbo.collection(collection).countDocuments(query.query);
let result = await cursor.toArray();
return {data: result, count:count};
}finally{
}
}
async aggregate(collection, specs){
try {
let cursor = dbo.collection(collection);
let aggCursor = cursor.aggregate(specs);
let result = await aggCursor.toArray();
return result.length == 1 ? result[0] : result;
}finally{
}
}
async distinct(collection, key, query){
try {
return await dbo.collection(collection).distinct(key, query);
}finally{
}
}
async update(collection, key, value){
let r;
try {
delete value._id;
r = await dbo.collection(collection).replaceOne(key, value, {upsert:true});
}finally{
return r;
}
}
async updateSet(collection, key, value){
let r;
try {
r = await dbo.collection(collection).updateMany(key, value);
}finally{
return r;
}
}
async remove(collection, key){
try {
await dbo.collection(collection).deleteMany(key);
}finally{
}
}
convertToObjectId(object, key, recursive, result){
if (object && object[key]){
if (Array.isArray(object[key])){
object[key].forEach((v, i, a)=>{
a[i] = this.ObjectId(v);
result && result.push(a[i]);
})
}else{
let oid = this.ObjectId(object[key])
object[key] = oid;
result && result.push(oid);
}
}
if (recursive){
for (var k in object){
if (typeof(object[k]) == 'object'){
this.convertToObjectId(object[k], key, recursive, result);
}
}
}
}
sanitizeQuery(q){
if (!q) return;
Object.getOwnPropertyNames(q).forEach(n=>{
if (n.startsWith('$')){
//sanitize $
console.warn('Deleting suspicious query key', n)
delete q[n];
}
if (typeof(q[n]) == 'object'){
this.sanitizeQuery(q[n]);
}
//prepare for DB
if (n.startsWith('*')){
let n1 = '$' + n.slice(1);
q[n1] = q[n];
delete q[n];
n = n1;
}
if (['$where', '$group', '$merge', '$lookup', '$accumulator', '$function'].includes(n)){
delete q[n];
console.warn('Deleting suspicious query key', n);
}
})
if (q.$oid){
q.$oid.forEach(o=>{
q[o] = this.ObjectId(q[o]);
})
delete q.$oid;
}
return q;
}
sanitizeProjection(p){
if (!p) return { _id: 1 };
let props = Object.getOwnPropertyNames(p);
props.forEach(n=>{
if (typeof p[n] == 'object'){
console.warn('Deleting suspicious projection key, object', n)
delete p[n]
}else if (!n.match(/^[0-9a-zA-Z\._\$\#\-\:]*$/)){
console.warn('Deleting suspicious projection key', n)
delete p[n]
}else if (typeof p[n] !== 'number' && !p[n].match(/^[0-9a-zA-Z\._\$\#\-]*$/)){
console.warn('Deleting suspicious projection value', n, p[n])
delete p[n]
}
})
props = Object.getOwnPropertyNames(p);
if (props.length == 0){
return { _id: 1 };
}
}
checkLimit(q){
if (!q) return;
if (!q.limit) q.limit = 100;
if (q.limit == 'all') delete q.limit;
}
ObjectId(id){
return new ObjectId(id);
}
}
export { Db };