Browse Source

A much cleaner method of cleaning objects before handing them to models to prevent injection bugs and erros with knex.

master
Zed A. Shaw 2 months ago
parent
commit
f3ca966cee
  1. 2
      api/user/payments.js
  2. 16
      lib/models.js
  3. 34
      lib/ormish.js
  4. 19
      tests/models/user.js

2
api/user/payments.js

@ -56,7 +56,7 @@ export const post = async (req, res) => {
assert(user_payment.user_id == api.user.id, "Wrong id for user_payment");
// TODO: this is weird, can I just use my clean method?
// BUG: why am I cloning this?
reply_data = Object.fromEntries(Object.entries(payment));
log.debug(reply_data);

16
lib/models.js

@ -38,11 +38,21 @@ export class User extends Model.from_table('user') {
}
}
static async register(user) {
if(user.password != user.password_repeat) {
/**
* Performs all the cleanup and checks needed for a registration. It will
* ensure that the password and password_repeat are the same, lowercase the email,
* clean out unwanted attrbiutes with User.clean, generate required keys, etc.
*
* @param {Object} attr - attributes usually from a web form
* @return {Object} undefined or the new user on success
*/
static async register(attr) {
let user = undefined;
if(attr.password != attr.password_repeat) {
return undefined;
} else {
delete user.password_repeat;
user = User.clean(attr);
}
// TODO: force emails to lowercase here rather than in the database?

34
lib/ormish.js

@ -22,40 +22,30 @@ await load_schema();
export class Model {
constructor(attr) {
assert(attr, "Must give attributes.");
for(let [key, value] of Object.entries(attr)) {
this[key] = value;
}
Object.assign(this, attr);
}
get table_name() {
return this.constructor.table_name;
static from(attr, also_remove=undefined) {
return new this(this.clean(attr, also_remove));
}
get schema() {
return this.constructor.schema;
}
static validate(attr) {
assert(attr, "Must give attributes to validate.");
const schema = this.schema;
let errors = Object.keys(attr).filter(k => schema[k] === undefined);
static clean(attr, also_remove=undefined) {
assert(attr, "Must give attributes to clean.");
return [errors.length === 0, errors];
}
let clean_entries = Object.entries(attr)
.filter(([k,v]) => k in this.schema);
static clean(attr, also_remove=[]) {
assert(attr, "Must give attributes to clean.");
const schema = this.schema;
let result = {};
if(also_remove) also_remove.forEach(k => delete clean_entries[k]);
for(let k of Object.keys(schema)) {
if(attr[k] !== undefined && !also_remove.includes(k)) {
result[k] = attr[k];
}
}
return Object.fromEntries(clean_entries);
}
return result;
get table_name() {
return this.constructor.table_name;
}
async destroy() {

19
tests/models/user.js

@ -2,14 +2,25 @@ import test from "ava";
import {random_user} from "../../lib/testing.js";
import { User, Payment } from "../../lib/models.js";
test('test that clean and from work', (t) => {
let user = random_user();
user.bad_key = "NOPE";
user.another = "GOODBYE";
let tester = User.from(user);
t.is(tester.bad_key, undefined);
t.is(tester.another, undefined);
user = User.clean(user);
t.is(user.bad_key, undefined);
t.is(user.another, undefined);
});
test('test user model basics work', async (t) => {
let user = random_user();
try {
const start = new User(user);
const [is_valid, errors] = User.validate(start)
t.is(is_valid, true, errors.join(","));
user.password_repeat = user.password;
let test1 = await User.register(user);

Loading…
Cancel
Save