/* This module have to be use in back as well front can be include in project with - >into a browser : - into a node.js : const Checkjson = require( `../nationchains/socialworld/contracts/Checkjson.js`); */ // --## const Checkjson = {}; Checkjson.schema = {}; Checkjson.schema.properties = {}; Checkjson.schema.properties.type = {}; Checkjson.schema.properties.type.string = (str) => typeof str === "string"; Checkjson.schema.properties.type.array = (val) => Array.isArray(val); Checkjson.schema.properties.type.number = (n) => typeof n === "number"; Checkjson.schema.properties.type.boolean = (n) => typeof n === "boolean"; Checkjson.schema.properties.type.integer = (n) => n != "" && !isNaN(n) && Math.round(n) == n; Checkjson.schema.properties.type.float = (n) => n != "" && !isNaN(n) && Math.round(n) != n; //not yet in json schema Checkjson.schema.properties.minLength = (str, min) => typeof str === "string" && str.length > parseInt(min); Checkjson.schema.properties.maxLength = (str, max) => typeof str === "string" && str.length < parseInt(max); Checkjson.schema.properties.multipleOf = (n, val) => typeof n === "number" && typeof val === "number" && parseFloat(n) / parseFloat(val) - Math.round(parseFloat(n) / parseFloat(val)) < 0.0000001; Checkjson.schema.properties.range = ( n, minimum, exclusiveMinimum, maximum, exclusiveMaximum ) => { //console.log(minimum,exclusiveMinimum,maximum, exclusiveMaximum,n) if (typeof n !== "number") return false; if (minimum && parseFloat(n) < parseFloat(minimum)) return false; if (exclusiveMinimum && parseFloat(n) <= parseFloat(exclusiveMinimum)) return false; if (maximum && parseFloat(n) > parseFloat(maximum)) return false; if (exclusiveMaximum && parseFloat(n) >= parseFloat(exclusiveMaximum)) return false; return true; }; Checkjson.schema.properties.pattern = (str, pattern) => { try { pattern = new RegExp(pattern); } catch (e) { console.log("err pattern in checkjon", pattern); return false; } return pattern.test(str); }; Checkjson.schema.properties.enum = (str, enumvalues) => { if (Array.isArray(enumvalues)) { return typeof str === "string" && enumvalues.includes(str); } else if (tribeId) { //enumvalues is a reference of objectname.key const { tribeId, obj, keyid } = enumvalues.split("."); return fs.existsSync( `${conf.dirtown}/tribes/${tribeId}/schema/${obj}/itm/${keyid}.json` ); } else { return true; } }; // to check a value for a pattern // Checkjson.schema.properties.pattern(value, properties[p].pattern) /** * * @param {string} str to test * @param {string} format keyworkd existing in Checkjson.schema.properties.format * @return null if format does not exist, true or false */ Checkjson.testformat=(str, format)=>{ if (!Checkjson.schema.properties.format[format]) { return null} return Checkjson.schema.properties.pattern(str, Checkjson.schema.properties.format[format]) } // see format https://json-schema.org/understanding-json-schema/reference/string.html#format // to check a just value with a format use Checkjson.testformat=(value, format) Checkjson.schema.properties.format = { "date-time": /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{1,3}/, stringalphaonly: /^[A-Za-z0-9]{3,}$/, time: /[0-2]\d:[0-5]\d:[0-5]\d\.\d{1,3}/, date: /\d{4}-[01]\d-[0-3]\d/, duration: / /, email: /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, "idn-email": / /, uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/, uri: / /, "uri-reference": / /, iri: / /, hostname: / /, "idn-hostname": / /, ipv4: /^([0–9]{1,3}.){3}.([0–9]{1,3})$/, ipv6: /^((([0–9A-Fa-f]{1,4}:){7}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){6}:[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){5}:([0–9A-Fa-f]{1,4}:)?[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){4}:([0–9A-Fa-f]{1,4}:){0,2}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){3}:([0–9A-Fa-f]{1,4}:){0,3}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){2}:([0–9A-Fa-f]{1,4}:){0,4}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){6}((b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b).){3}(b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b))|(([0–9A-Fa-f]{1,4}:){0,5}:((b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b).){3}(b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b))|(::([0–9A-Fa-f]{1,4}:){0,5}((b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b).){3}(b((25[0–5])|(1d{2})|(2[0–4]d)|(d{1,2}))b))|([0–9A-Fa-f]{1,4}::([0–9A-Fa-f]{1,4}:){0,5}[0–9A-Fa-f]{1,4})|(::([0–9A-Fa-f]{1,4}:){0,6}[0–9A-Fa-f]{1,4})|(([0–9A-Fa-f]{1,4}:){1,7}:))$/, telephonefr: /^0[1-9][0-9]{9}$/, telephoneinter: /^\+*(\d{3})*[0-9,\-]{8,}/, password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&.])[A-Za-z\d$@$!%*?&.{}:|\s]{8,}/, postalcodefr: /(^\d{5}$)|(^\d{5}-\d{4}$)/, pgppublickey: /^-----BEGIN PGP PUBLIC KEY BLOCK-----(\n|\r|\r\n)(\n|\r|\r\n)([0-9a-zA-Z\+\/=]*(\n|\r|\r\n))*-----END PGP PUBLIC KEY BLOCK-----(\n|\r|\r\n)?$/gm, pgpprivatekey: /^-----BEGIN PGP PRIVATE KEY BLOCK-----(\n|\r|\r\n)(\n|\r|\r\n)([0-9a-zA-Z\+\/=]*(\n|\r|\r\n))*-----END PGP PRIVATE KEY BLOCK-----(\n|\r|\r\n)?$/gm, }; Checkjson.schema.properties.default; Checkjson.schema.validation = (schema) => { /*validate a schema structure*/ const multimsg = []; const res = {}; if (schema.properties) { Object.keys(schema.properties).forEach((p) => { const properties = schema.properties; if ( properties[p].type && typeof properties[p].type === "string" && !Checkjson.schema.properties.type[properties[p].type] ) { multimsg.push({ ref: "Checkjson", msg: "schemaerrtypedoesnotexist", data: { propertie: p, type: properties[p].type }, }); } if ( properties[p].type && typeof properties[p].type === "object" && Array.isArray(properties[p].type) ) { properties[p].type.forEach((tp) => { if (!Checkjson.schema.properties.type[tp]) multimsg.push({ ref: "Checkjson", msg: "schemaerrtypedoesnotexist", data: { propertie: p, type: properties[p].type }, }); }); } if ( properties[p].format && !Checkjson.schema.properties.format[properties[p].format] ) { multimsg.push({ ref: "Checkjson", msg: "schemaerrformatdoesnotexist", data: { propertie: p, format: properties[p].format }, }); } if (properties[p].enum && !Array.isArray(properties[p].enum)) { multimsg.push({ ref: "Checkjson", msg: "schemaerrenumnotarray", data: { propertie: p, enum: properties[p].enum }, }); } }); } // 406 means not acceptable if (multimsg.length > 0) { res.status = 406; res.multimsg = multimsg; } else { res.status = 200; res.ref = "Checkjson"; res.msg = "validcheck"; } return res; }; /** * Check data with a schema * * @param {object} schema a json schema * @param {*} data some data to check using schema * @param {*} withschemacheck boolean that force a schema check (usefull on modification schema) * @returns {status: 200, ref:"Checkjson", msg:"validcheck", data:{itm:object}} * {status:417, multimsg:[{re,msg,data}],data:{itm:object}} */ Checkjson.schema.data = (schema, data, withschemacheck) => { /* validate a data set with a schema in a context ctx */ /* console.log('#################') console.log(schema); console.log('---------') console.log(data) */ if (withschemacheck) { const validschema = Checkjson.schema.validation(schema); if (validschema.status != 200) return validschema; } const multimsg = []; const res = { status: 200, data: { itm: data }, }; if (schema.properties) { const properties = schema.properties; Object.keys(properties).forEach((p) => { //type is mandatory in a propertie if (data[p]) { const typlist = properties[p].type && typeof properties[p].type === "string" ? [properties[p].type] : properties[p].type; let valid = false; typlist.forEach((typ) => { // at least one test have to be ok if (Checkjson.schema.properties.type[typ](data[p])) valid = true; }); if (!valid) multimsg.push({ ref: "Checkjson", msg: "dataerrpropertie", data: { key: p, value: data[p] }, }); if ( properties[p].minLength && !Checkjson.schema.properties.minLength( data[p], properties[p].minLength ) ) { multimsg.push({ ref: "Checkjson", msg: "dataerrpropertie", data: { key: p, value: data[p], minLength: properties[p].minLength, }, }); } if ( properties[p].maxLength && !Checkjson.schema.properties.maxLength( data[p], properties[p].maxLength ) ) { multimsg.push({ ref: "Checkjson", msg: "dataerrpropertie", data: { key: p, value: data[p], maxLength: properties[p].maxLength, }, }); } if ( properties[p].multipleOf && !Checkjson.schema.properties.multipleOf( data[p], properties[p].multipleOf ) ) { multimsg.push({ ref: "Checkjson", msg: "dataerrpropertie", data: { key: p, value: data[p], multipleOf: properties[p].multipleOf, }, }); } if ( properties[p].minimum || properties[p].maximum || properties[p].exclusiveMinimum || properties[p].exclusiveMaximum ) { // test range if ( !Checkjson.schema.properties.range( data[p], properties[p].minimum, properties[p].exclusiveMinimum, properties[p].maximum, properties[p].exclusiveMaximum ) ) { multimsg.push({ ref: "Checkjson", msg: "dataerrpropertie", data: { key: p, value: data[p], minimum: properties[p].minimum, maximum: properties[p].maximum, exclusiveMinimum: properties[p].exclusiveMinimum, exclusiveMaximum: properties[p].exclusiveMaximum, }, }); } } if ( properties[p].enum && !Checkjson.schema.properties.enum(data[p], properties[p].enum) ) { multimsg.push({ ref: "Checkjson", msg: "dataerrpropertie", data: { key: p, value: data[p], enumlst: properties[p].enum }, }); } if (properties[p].format) { properties[p].pattern = Checkjson.schema.properties.format[properties[p].format]; } if ( properties[p].pattern && !Checkjson.schema.properties.pattern(data[p], properties[p].pattern) ) { multimsg.push({ ref: "Checkjson", msg: "dataerrpropertie", data: { key: p, value: data[p], pattern: properties[p].pattern }, }); } } else if (schema.required && schema.required.includes(p)) { multimsg.push({ ref: "Checkjson", msg: "dataerrpropertierequired", data: { key: p, required: true }, }); } }); } //end properties if (schema.apxid) { res.data.apxid = data[schema.apxid]; } if (multimsg.length > 0) { res.status = 417; res.multimsg = multimsg; } else { res.status = 200; res.ref = "Checkjson"; res.msg = "validcheck"; } return res; }; if (typeof module !== "undefined") module.exports = Checkjson;