")
461 | .text(dp).html()))
462 | .append($("
").html($("")
463 | .text(r[d]).html()))).html();
464 | }
465 | }
466 | function deepdive(_, _, row, el) {
467 | try {
468 | var tinfo = el.closest('tr').data('uniqueid');
469 | if(tinfo)
470 | $('#detailtag').html("("+tinfo+")");
471 | else
472 | $('#detailtag').html('');
473 | } catch(err) {
474 | console.log("Ignore this error");
475 | $('#detailtag').html('');
476 | }
477 | /* Show the updaterecord button by default and hide it later
478 | if user is not admin and not self */
479 | $('#updaterecord').show();
480 | $('#cvereject').addClass("d-none");
481 | $('#cvedetails').addClass('d-none');
482 | if("username" in row) {
483 | if(check_admin() || (row.username == client.user)) {
484 | $('#updaterecord').show();
485 | $('.selfadmin').show();
486 | } else {
487 | $('#updaterecord').hide();
488 | $('.selfadmin').hide();
489 | }
490 | $('#updaterecord').html("Update User");
491 | } else if(("cve_id" in row) && ("state" in row)) {
492 | $('#cveUpdateModal .mtitle').html("("+row.cve_id+")");
493 | if (row.state == "RESERVED") {
494 | $('#updaterecord').html("Edit & Publish CVE").show();
495 | $('#cveUpdateModal .cveupdate').html("Publish CVE");
496 | $('#cvedetails').addClass('d-none');
497 | $('#cvereject').removeClass('d-none');
498 | } else if (row.state == "PUBLISHED") {
499 | $('#updaterecord').html("Update CVE").show();
500 | $('#cvedetails').removeClass('d-none');
501 | $('#cveUpdateModal .cveupdate').html("Update CVE");
502 | $('#cvereject').removeClass("d-none");
503 | } else {
504 | if(row.state == "REJECTED") {
505 | $('#cvereject').addClass('d-none');
506 | $('#cvedetails').removeClass('d-none');
507 | }
508 | $('#updaterecord').hide();
509 | }
510 | } else
511 | $('#updaterecord').hide();
512 | display_object(row);
513 | $('#deepDive').data('crecord',row).modal();
514 | }
515 | async function display_cvedetails(cve) {
516 | if(!cve)
517 | cve = $('#deepDive').data('crecord').cve_id;
518 | let f = await client.getcvedetail(cve);
519 | if("error" in f) {
520 | swal_error("Unable to view CVE due to error: " + f.error +
521 | ": " + f.message);
522 | return;
523 | }
524 | if(("containers" in f) && ("cna" in f.containers))
525 | display_object(f.containers.cna);
526 | else
527 | swal_error("Required information in cna.container is not " +
528 | "available or missing ");
529 | }
530 | function swapout(w) {
531 | $(w).parent().find('table tbody tr').toggleClass('d-none');
532 | if($(w).html().indexOf('View') > -1)
533 | $(w).html('Hide JSON');
534 | else
535 | $(w).html('View JSON');
536 | }
537 | function display_object(obj) {
538 | let tjson = ' '+
539 | ' ' +
540 | JSON.stringify(obj,null,3) + ' | ';
541 | let alink = ' View JSON';
543 | let ttable = ' ';
544 | var html = Object.keys(obj).reduce(function(h,d) {
545 | return objwalk(h,d,obj);
546 | },alink+ttable+""+tjson);
547 | $('#deepDive .modal-body').html(html+' ');
548 | }
549 | function add_user_modal() {
550 | $('#addUserModal').modal();
551 | $('#addUserModal form').trigger('reset');
552 | $('.addUserModal .form-control').removeClass('is-valid is-invalid');
553 | $('#addUserModal .mtitle').html("Add User");
554 | $('#addUserModal').removeClass("updateUser").addClass("addUser");
555 | $('#addUserModal .updateuser').hide();
556 | $('#addUserModal .adduser').show();
557 | if(!('usertable' in client)) {
558 | console.log("Creating users table in the background");
559 | show_users_table();
560 | $('#users-tab').tab('show');
561 | }
562 | }
563 | function user_active_view(active) {
564 | if(active) {
565 | $('#addUserModal .active').prop({checked:true}).addClass('enabled');
566 | $('#addUserModal span.round').prop({title:'Active'});
567 | $('#addUserModal span.uspan').removeClass('text-danger')
568 | .addClass('text-primary').html(' [Active] ');
569 | } else {
570 | $('#addUserModal .active').prop({checked:false})
571 | .removeClass('enabled');
572 | $('#addUserModal span.round').prop({title:'Inactive'});
573 | $('#addUserModal span.uspan').removeClass('text-primary')
574 | .addClass('text-danger').html(' [Inactive] ');
575 | }
576 | }
577 | function user_update_modal(mr) {
578 | $('#addUserModal').modal();
579 | $('#addUserModal').removeClass("addUser").addClass("updateUser");
580 | /* update button remains hidden until some values change in the form*/
581 | $('#updateButton').hide();
582 | $('#addUserModal .adduser').hide();
583 | $('#addUserModal .mtitle').html("Update User ("+mr.username+")");
584 | $('#addUserModal .username').val(mr.username).data('oldvalue',mr.username);
585 | $('#addUserModal .form-control').removeClass('is-valid is-invalid');
586 | if('name' in mr) {
587 | if('first' in mr.name)
588 | $('#addUserModal .name_first').val(mr.name.first)
589 | .data('oldvalue',mr.name.first);
590 | if('last' in mr.name)
591 | $('#addUserModal .name_last').val(mr.name.last)
592 | .data('oldvalue',mr.name.last);
593 | }
594 | if('active' in mr)
595 | user_active_view(mr.active);
596 | if(mr.authority.active_roles.length) {
597 | /* Handle user roles currently only ADMIN or Nothing*/
598 | let vroles = mr.authority.active_roles.join(",")
599 | $('#addUserModal .active_roles').val(vroles).data('oldvalue',vroles);
600 | } else {
601 | $('#addUserModal .active_roles').val('');
602 | }
603 | }
604 | function checkchange(w) {
605 | if(get_deep(w,'validity.valid') != undefined) {
606 | if(w.validity.valid == false)
607 | $(w).removeClass('is-valid').addClass('is-invalid');
608 | if (w.validity.valid == true)
609 | $(w).removeClass('invalid').addClass('is-valid');
610 | }
611 | if($('#addUserModal').hasClass("updateUser")) {
612 | if(($(w).data('oldvalue') != $(w).val()) && $(w).hasClass('is-valid'))
613 | $('#updateButton').show();
614 | }
615 | }
616 | function vreplace(s,v) {
617 | var vr = v.split("|");
618 | for(var i=0; i li.erow:nth-of-type(n+2)').remove();
629 | $('#cveform').trigger('reset');
630 | $('#cveUpdateModal').modal();
631 | var mr = $('#deepDive').data('crecord');
632 | if(('state' in mr) && (mr.state == 'PUBLISHED')) {
633 | let c = await client.getcvedetail(mr.cve_id);
634 | console.log(c);
635 | if(('containers' in c) && (c.containers.cna))
636 | json_edit(JSON.stringify(c.containers.cna,null,3));
637 | else if('error' in c)
638 | swal_error("Error in fetching details of CVE "+c.error+" : "+
639 | c.message);
640 | else
641 | swal_error("Unknown error when fetching details of CVE. "+
642 | "See console log for details");
643 | } else {
644 | let mjson = JSON.stringify(_cna_template,null,2)
645 | .replace(/\$\{([^\}]+)\}/g,vreplace);
646 | json_edit(mjson);
647 | }
648 | }
649 | function mupdate() {
650 | var mr = $('#deepDive').data('crecord');
651 | if(!mr)
652 | return;
653 | $('#deepDive').modal('hide');
654 | if('username' in mr) {
655 | user_update_modal(mr);
656 | } else {
657 | cve_update_modal(mr);
658 | }
659 | }
660 | async function show_table(fun,fvars,msg,tag,fld,pmd,clm,tbn,uid,show) {
661 | if(show) {
662 | if(tbn in client) {
663 | top_alert("success","Showing Cached data. If needed click on Refresh Icon.",1000);
664 | return;
665 | }
666 | }
667 | let m;
668 | try {
669 | m = await client[fun].apply(client,fvars);
670 | } catch(err) {
671 | swal_error("Error in collecting data, potentially network error OR "+
672 | " asynchronous decryption in progress. "+
673 | "Try again in a few seconds.");
674 | console.log(err);
675 | return;
676 | }
677 | if(!(fld in m)) {
678 | Swal.fire({
679 | title: "No data to display!",
680 | text: msg,
681 | icon: "warning",
682 | confirmButtonText: "OK",
683 | timer: 1800
684 | });
685 | return;
686 | }
687 | /* totalCount itemsPerPage pageCount currentPage prevPage nextPage */
688 | if(('totalCount' in m) && (m.totalCount > m[fld].length)) {
689 | for(var i=m[fld].length; i nameB) {
748 | return 1;
749 | }
750 | return 0;
751 | }
752 | function show_users_table(show) {
753 | let fun = "listusers";
754 | let tag = "USER-";
755 | let fld = "users";
756 | let uid = "username";
757 | let tbn = "usertable";
758 | let msg = "No Users to display";
759 | let pmd = {active: "UNKNOWN"};
760 | let clm = [{field:'name', title:'Full name', formatter: gname,
761 | sortable:true, sorter:gsort},
762 | {field:'username', title:'Username',sortable: true},
763 | {field: 'active', title: 'Active',sortable: true}];
764 | show_table(fun,undefined,msg,tag,fld,pmd,clm,tbn,uid,show);
765 | }
766 | function wdate(reserved,row) {
767 | if(get_deep(row,'time.modified'))
768 | return get_deep(row,'time.modified');
769 | return reserved;
770 | }
771 | function wsort(d1,d2,row1,row2) {
772 | let dateA = wdate(d1,row1);
773 | let dateB = wdate(d2,row2);
774 | if (dateA < dateB) {
775 | return -1;
776 | }
777 | if (dateA > dateB) {
778 | return 1;
779 | }
780 | return 0;
781 | }
782 | function show_cve_table(show) {
783 | let fun = "getcveids";
784 | let year = $('#year').val();
785 | let fvars = undefined;
786 | if(parseInt(year) > 0) {
787 | /* Add Year to the getcveids API endpoint */
788 | fvars = [undefined,undefined,{cve_id_year: year}];
789 | }
790 | let tag = "CVE-9999-";
791 | let fld = "cve_ids";
792 | let uid = "cve_id";
793 | let tbn = "cvetable";
794 | let msg = "No CVE data to display";
795 | let pmd = {state: "UNKNOWN",reserved: (new Date(0)).toISOString()};
796 | let clm = [{field:'cve_id', title: 'CVE', sortable: true},
797 | {field: 'state', title: 'State', sortable: true},
798 | {field: 'reserved', title: 'Date', sortable: true,
799 | formatter: wdate, sorter: wsort}];
800 | show_table(fun,fvars,msg,tag,fld,pmd,clm,tbn,uid,show);
801 | }
802 | async function reserve() {
803 | let vars = {};
804 | $('#reserveCVEModal .form-control').each(function(_,x) {
805 | vars[x.name] = $(x).val();
806 | });
807 | $('#reserveCVEModal').modal('hide');
808 | let y = await client.reservecve(vars.amount,vars.cve_year,vars.batch_type);
809 | if("error" in y) {
810 | swal_error("Error while logging in: "+y.error+" "+y.message);
811 | return;
812 | } else if('cve_ids' in y) {
813 | Swal.fire({
814 | title: "CVE Reserve success!",
815 | text: "Reserved " + y.cve_ids.length+" CVE's.",
816 | icon: "success",
817 | timer: 1800
818 | });
819 | for(var i=0; i[" + String(f.active)+"]",4000);
1006 | setTimeout(function() {
1007 | /* Just clear out warning */
1008 | lock_unlock(0,w);
1009 | $('#addUserModal').modal('hide');
1010 | },2000);
1011 | setTimeout(function() {
1012 | f.warn = 0;
1013 | client.usertable.bootstrapTable('updateByUniqueId',username,f);
1014 | },4000);
1015 | }
1016 |
1017 | }
1018 | function set_copy_pass(secret){
1019 | $("#cpassword").remove();
1020 | var ppass = $('').val(secret).attr("id","cpassword").
1021 | addClass("passform").on("click",selectpass).
1022 | attr("readonly","readonly");
1023 | $('#addUserModal').append(ppass);
1024 | selectpass("cpassword");
1025 | }
1026 | async function adduser() {
1027 | let usermodel = {username: "", name: {first:"",last: ""},
1028 | active: true,authority: {active_roles: []} };
1029 | let username = $('#addUserModal .username').val();
1030 | let fname = $('#addUserModal .name_first').val() || "";
1031 | let lname = $('#addUserModal .name_last').val() || "";
1032 | let role = $('#addUserModal .active_roles').val();
1033 | if(!username) {
1034 | $('#addUserModal .username').addClass('is-invalid');
1035 | return;
1036 | };
1037 | $('#addUserModal .username').removeClass('is-invalid');
1038 | usermodel['username'] = username.toLowerCase();
1039 | usermodel['name'] = { first: fname, last: lname};
1040 | if(role)
1041 | usermodel['authority']['active_roles'].push(role);
1042 | let f = await client.createuser(usermodel);
1043 | if('error' in f) {
1044 | swal_error(f.error + ": " + f.message);
1045 | return;
1046 | }
1047 | if('created' in f) {
1048 | let fn = simpleCopy(f.created);
1049 | fn.new = 1;
1050 | client.usertable.bootstrapTable('insertRow',
1051 | {index: 0,
1052 | row: fn});
1053 | set_copy_pass(fn.secret);
1054 | Swal.fire({
1055 | title: "User Created!",
1056 | text: f.message + " API-Key secret is copied to your clipboard!",
1057 | icon: "success",
1058 | timer: 3800
1059 | }).then(function() {
1060 | $('#users-tab').click();
1061 | setTimeout(function() {
1062 | fn.new = 0;
1063 | client.usertable
1064 | .bootstrapTable('updateByUniqueId',{id: username,
1065 | row: fn,
1066 | replace:true});
1067 |
1068 | },1000);
1069 | });
1070 | }
1071 | $('#addUserModal').modal('hide');
1072 | }
1073 | function get_json_data() {
1074 | try {
1075 | return JSON.parse($('#mjson .jsoneditor')[0]
1076 | .env.editor.getValue());
1077 | } catch (err) {
1078 | console.log(err);
1079 | swal_error("Error in collecting JSON. See console log for details");
1080 | return {};
1081 | }
1082 |
1083 | }
1084 | function from_json(w) {
1085 | let json_data = get_json_data();
1086 | if(!json_data)
1087 | return;
1088 | $('#nice .frow').each(function(_,el) {
1089 | var field = $(el).data("rclass");
1090 | if(field in json_data) {
1091 | let diff = json_data[field].length - $(el).find("> .erow").length;
1092 | if(diff > 0) {
1093 | /* Add elements */
1094 | for(var i=1; i <= diff; i++)
1095 | $(el).find(".addrow").click();
1096 | } else if (diff < 0) {
1097 | /* Remove elements */
1098 | for(var i=1; i <= Math.abs(diff); i++)
1099 | $(el).find(".deleterow").click();
1100 | }
1101 | /* Check if Range is selected for affected version */
1102 | var versionRange = undefined;
1103 | json_data[field].forEach(function(x) {
1104 | if('versions' in x) {
1105 | x.versions.forEach(function(y) {
1106 | /* if( ('lessThan' in y) || ('lessThanOrEqual' in y)) */
1107 | ['lessThan','lessThanOrEqual'].forEach(function(q) {
1108 | if(q in y) {
1109 | versionRange = q
1110 | $(el).find('.versionRangeType').val(q).trigger('change');
1111 | }
1112 | })
1113 | })
1114 | }
1115 | });
1116 | $(el).find('.versionRangeEnabled').prop('checked',versionRange ? true: false)
1117 | .trigger('change');
1118 |
1119 | }
1120 | });
1121 | $('#nice .form-control').each(function(_,v) {
1122 | let props = $(v).data("field");
1123 | if(props) {
1124 | let oval = get_deep(json_data,props);
1125 | if(oval && oval[0] != '$') {
1126 | /* Value map exists and does not begin with $ */
1127 | $(v).val(oval);
1128 | if(oval != $(v).val()) {
1129 | /* In case of select field */
1130 | add_option(v,oval,oval,1);
1131 | }
1132 | clearoff(v);
1133 | }
1134 | }
1135 | });
1136 | }
1137 | async function publish_cve() {
1138 | try {
1139 | if($('#nice-or-json').find(".active.show").attr("id") == "nice") {
1140 | if(to_json() == false) {
1141 | $('#cveform .is-invalid').focus();
1142 | swal_error("Some required fields are missing or incomplete");
1143 | return;
1144 | }
1145 | }
1146 | let editor = $('#mjson .jsoneditor')[0].env.editor;
1147 | let pubcve = JSON.parse(editor.getValue());
1148 | let mr = $('#deepDive').data('crecord');
1149 | /* Override some fields on submit*/
1150 | if(get_deep(client,'userobj.org_UUID') && client.org)
1151 | pubcve["providerMetadata"] = { orgId: client.userobj.org_UUID,
1152 | shortName: client.org };
1153 | if(get_deep(client,'constructor.name') && client._version)
1154 | pubcve["x_generator"] = {engine: client.constructor.name + "/" +
1155 | client._version };
1156 | let cve = mr.cve_id;
1157 | let ispublic = mr.state != "RESERVED";
1158 | let rejected = false;
1159 | let d = await client.publishcve(cve,pubcve,ispublic,rejected);
1160 | if("error" in d) {
1161 | swal_error("Failed to publish CVE, Error : "+d.error);
1162 | console.log(d);
1163 | return;
1164 | }
1165 | if(("created" in d) || ("updated" in d)) {
1166 | let note = "Published";
1167 | let fnote = "created";
1168 | if(ispublic) {
1169 | note = "Updated";
1170 | fnote = "updated";
1171 | }
1172 | Swal.fire({
1173 | title: "CVE "+note+" Successfully!",
1174 | text: d.message,
1175 | icon: "success",
1176 | timer: 1800
1177 | });
1178 | let u = client.cvetable.bootstrapTable('getRowByUniqueId',cve);
1179 | u.state = get_deep(d,fnote+'.cveMetadata.state');
1180 | let modified = get_deep(d,fnote+'.cveMetadata.datePublished');
1181 | if(modified)
1182 | set_deep(u,'time.modified',modified);
1183 | u.new = 1;
1184 | client.cvetable.bootstrapTable('updateByUniqueId',{id: cve,
1185 | row: u });
1186 | $('#cveUpdateModal').modal('hide');
1187 | } else {
1188 | console.log(d);
1189 | swal_error("Unknown error CVE could not be updated. See console "+
1190 | " log for details!");
1191 | }
1192 | }catch(err) {
1193 | console.log(err);
1194 | swal_error("Could not publish this CVE. Fix the errors please!");
1195 | }
1196 | }
1197 | function to_json(w) {
1198 | let json_data = get_json_data();
1199 | let value_check = true;
1200 | $('#nice .form-control').not('.d-none').each(function(_,v) {
1201 | if($(v).val()) {
1202 | let props = $(v).data("field");
1203 | if(!props) return;
1204 | json_data = set_deep(json_data,props,$(v).val());
1205 | $(v).removeClass('is-invalid').addClass('is-valid');
1206 | } else {
1207 | if(v.required) {
1208 | value_check = false;
1209 | $(v).removeClass('is-valid').addClass('is-invalid');
1210 | } else {
1211 | let props = $(v).data("field");
1212 | if(!props) return;
1213 | /* Delete the field if exists */
1214 | json_data = set_deep(json_data,props,undefined);
1215 | }
1216 | }
1217 | });
1218 | let editor = $('#mjson .jsoneditor')[0].env.editor;
1219 | editor.setValue(JSON.stringify(json_data,null,2));
1220 | return value_check;
1221 | }
1222 | function update_related(w) {
1223 | /* Function to update the data-field of a related item*/
1224 | /* data-related="versionRangeValue" data-relatedfield="affected.0.versions.0.$" */
1225 | let related = $(w).data("related");
1226 | if($(w).val()) {
1227 | let field = $(w).data("relatedfield").replace("$",$(w).val());
1228 | $(w).parent().find("."+related).attr("data-field",field);
1229 | } else {
1230 | $(w).parent().find("."+related).removeAttr("data-field");
1231 | }
1232 | }
1233 | function clearoff(w) {
1234 | if($(w).val() && (get_deep(w,'validity.valid') == true))
1235 | $(w).removeClass('is-invalid').addClass('is-valid');
1236 | }
1237 | function disable_encryption() {
1238 | if(!('dfetch' in client)) {
1239 | console.log("Encryption seems to be disabled already");
1240 | return;
1241 | }
1242 | check_create_key(client.user).then(function(ekey) {
1243 | let encBuffer = URItoarrayBuffer(client.key);
1244 | decryptMessage(encBuffer,ekey.privateKey)
1245 | .then(function(encKey) {
1246 | client.key = encKey;
1247 | store.setItem(store_tag+"key",client.key);
1248 | $('.encryption').toggleClass("d-none");
1249 | client.rfetch = client.dfetch;
1250 | delete client.dfetch;
1251 | top_alert("warning","Encryption is now disabled for your API keys!");
1252 | });
1253 | });
1254 | }
1255 | function activate_encryption() {
1256 | if('dfetch' in client) {
1257 | console.log("Encrypt/Decrypt API is already enabled ");
1258 | return;
1259 | }
1260 | client.dfetch = client.rfetch;
1261 | client.rfetch = function(path,opts,qvars) {
1262 | return check_create_key(client.user).then(function(ekey) {
1263 | let encKey = client.key;
1264 | let encBuffer = URItoarrayBuffer(client.key);
1265 | return decryptMessage(encBuffer,ekey.privateKey)
1266 | .then(function(rawKey) {
1267 | client.key = rawKey;
1268 | return client.dfetch(path,opts,qvars)
1269 | .then(function(u) {
1270 | client.key = encKey;
1271 | return u;
1272 | });
1273 | });
1274 | });
1275 | };
1276 | $('.encryption').toggleClass("d-none");
1277 | top_alert("success","Encryption is now enabled for your API Key",4000);
1278 | }
1279 | function enable_encryption() {
1280 | $.getScript("encrypt-storage.js").done(function() {
1281 | try {
1282 | let m = new URL(client.key);
1283 | console.log("Already Encrypted");
1284 | return;
1285 | } catch (_) {
1286 | /* Encrypt storage using RSA keys*/
1287 | try {
1288 | check_create_key(client.user).then(function(newkey) {
1289 | encryptMessage(client.key,newkey.publicKey)
1290 | .then(function(encBuffer) {
1291 | arrayBuffertoURI(encBuffer)
1292 | .then(function(encURL) {
1293 | client.key = encURL;
1294 | store.setItem(store_tag+"key",encURL);
1295 | activate_encryption();
1296 | });
1297 | });
1298 | });
1299 | } catch(err) {
1300 | console.log(err);
1301 | top_alert("warning","Encrypting API key failed, see console log for errors");
1302 | };
1303 | }
1304 | });
1305 | }
1306 | async function showorg() {
1307 | let m = await client.getorg(client.org);
1308 | display_object(m);
1309 | $('#deepDive').modal();
1310 | $('#updaterecord').hide();
1311 | }
1312 | async function reject_cve(confirm) {
1313 | $('#deepDive').modal('hide');
1314 | var mr = $('#deepDive').data('crecord');
1315 | if(!('cve_id' in mr))
1316 | swal_error("Error there seems to no CVE number selected");
1317 | if(confirm) {
1318 | let reason = $('#rejectcveModal .description').val();
1319 | if(reason.length < 3) {
1320 | swal_error("Please provide a description or reason for rejection of this CVE");
1321 | return;
1322 | }
1323 | let rejcve = {"rejectedReasons": [{"lang": "en","value": reason }]};
1324 | if(get_deep(client,'userobj.org_UUID') && client.org)
1325 | rejcve["providerMetadata"] = { orgId: client.userobj.org_UUID,
1326 | shortName: client.org };
1327 | if(get_deep(client,'constructor.name') && client._version)
1328 | rejcve["x_generator"] = {engine: client.constructor.name + "/" +
1329 | client._version };
1330 | let cve = mr.cve_id;
1331 | let ispublic = mr.state != "RESERVED";
1332 | let rejected = true;
1333 | let d = await client.publishcve(cve,rejcve,ispublic,rejected);
1334 | if("error" in d) {
1335 | swal_error("Failed to publish CVE, Error : "+d.error);
1336 | console.log(d);
1337 | return;
1338 | }
1339 | if(("created" in d) || ("updated" in d)) {
1340 | let note = "Rejected";
1341 | let fnote = "created";
1342 | if(ispublic) {
1343 | note = "Updated";
1344 | fnote = "updated";
1345 | }
1346 | Swal.fire({
1347 | title: "CVE "+note+" Successfully!",
1348 | text: d.message,
1349 | icon: "success",
1350 | timer: 1800
1351 | });
1352 | $('#rejectcveModal').modal("hide");
1353 | let u = client.cvetable.bootstrapTable('getRowByUniqueId',cve);
1354 | u.state = get_deep(d,fnote+'.cveMetadata.state');
1355 | let modified = get_deep(d,fnote+'.cveMetadata.datePublished');
1356 | if(modified)
1357 | set_deep(u,'time.modified',modified);
1358 | u.new = 1;
1359 | client.cvetable.bootstrapTable('updateByUniqueId',{id: cve,
1360 | row: u });
1361 | $('#cveUpdateModal').modal('hide');
1362 | } else {
1363 | console.log(d);
1364 | swal_error("Unknown error CVE could not be updated. See console "+
1365 | " log for details!");
1366 | }
1367 | } else {
1368 | $('#rejectcveModal').modal()
1369 | $('#rejectcveModal').find(".cve").val(mr.cve_id);
1370 | }
1371 |
1372 | }
1373 |
--------------------------------------------------------------------------------
/encrypt-storage.js:
--------------------------------------------------------------------------------
1 | /* Encryption API using JavaScript native crypto.js and indexeDB for storing private keys */
2 | const encrypt_storage_version = "1.1.14";
3 | async function encryptMessage(message,publicKey) {
4 | let encoded = new TextEncoder().encode(message);
5 | let ciphertext = await window.crypto.subtle.encrypt(
6 | {
7 | name: "RSA-OAEP"
8 | },
9 | publicKey,
10 | encoded
11 | );
12 | return ciphertext;
13 | }
14 | async function decryptMessage(ciphertext,privateKey) {
15 | let decrypted = await window.crypto.subtle.decrypt(
16 | {
17 | name: "RSA-OAEP"
18 | },
19 | privateKey,
20 | ciphertext
21 | );
22 |
23 | let dec = new TextDecoder();
24 | return dec.decode(decrypted);
25 | }
26 | async function arrayBuffertoURI(arrayBuffer) {
27 | let blob = new Blob([arrayBuffer]);
28 | return new Promise((resolve) => {
29 | let reader = new FileReader()
30 | reader.onloadend = function() {
31 | resolve(reader.result);
32 | };
33 | reader.readAsDataURL(blob);
34 | });
35 | }
36 | function URItoarrayBuffer(URI) {
37 | var byteString = atob(URI.split(',')[1]);
38 | var arrayBuffer = new ArrayBuffer(byteString.length);
39 | var _ia = new Uint8Array(arrayBuffer);
40 | for (var i = 0; i < byteString.length; i++) {
41 | _ia[i] = byteString.charCodeAt(i);
42 | }
43 | return arrayBuffer;
44 | }
45 |
46 |
47 | async function sha256sum(msg) {
48 | let enc = new TextEncoder().encode(msg);
49 | const buff = await crypto.subtle.digest('SHA-256', enc);
50 | const barray = Array.from(new Uint8Array(buff));
51 | let hex = barray.map(function(b) {
52 | return b.toString(16).padStart(2, '0');
53 | }).join('');
54 | return hex;
55 | };
56 | function dbManager(user,key,sum) {
57 | return new Promise(function(resolve, reject) {
58 | var indexedDB = window.indexedDB || window.mozIndexedDB
59 | || window.webkitIndexedDB || window.msIndexedDB
60 | || window.shimIndexedDB;
61 | var open = indexedDB.open("cve-services.apikeyStore", 1);
62 | open.onupgradeneeded = function() {
63 | var db = open.result;
64 | if (!db.objectStoreNames.contains("keyStore")) {
65 | var store = db.createObjectStore("keyStore",
66 | {keyPath: "user"});
67 | var index = store.createIndex("sigIndex", ["sum.sha256"]);
68 | }
69 | };
70 | open.onsuccess = function() {
71 | var db = open.result;
72 | var tx = db.transaction("keyStore", "readwrite");
73 | var store = tx.objectStore("keyStore");
74 | if(key) {
75 | store.put({user: user, key: key, sum: sum});
76 | } else {
77 | if(user) {
78 | var getUser = store.get(user);
79 | getUser.onsuccess = function(q) {
80 | resolve(q);
81 | };
82 | } else if(sum.sha256) {
83 | var index = store.index("sigIndex");
84 | var getSum = index.get([sum.sha256]);
85 | getSum.onsuccess = function(q) {
86 | resolve(q);
87 | };
88 | } else {
89 | reject("A user or a checksum is required");
90 | }
91 | };
92 | tx.oncomplete = function() {
93 | db.close();
94 | };
95 | }
96 | });
97 | }
98 | async function save_key(user,key) {
99 | let fpb = await window.crypto.subtle.exportKey("jwk", key.publicKey);
100 | let fpr = await window.crypto.subtle.exportKey("jwk", key.privateKey);
101 | let exportKey = {epr: fpr, epb: fpb};
102 | let sum = {sha256: await sha256sum(fpb.n)};
103 | dbManager(user,exportKey,sum);
104 | return exportKey;
105 | }
106 | async function import_key({epr,epb}) {
107 | let prkey = await window.crypto.subtle.importKey("jwk",epr,{name:"RSA-OAEP", hash: {name: "SHA-256"}},false,['decrypt']);
108 | let pbkey = await window.crypto.subtle.importKey("jwk",epb,{name:"RSA-OAEP", hash: {name: "SHA-256"}},false,['encrypt']);
109 | return { privateKey: prkey, publicKey: pbkey };
110 | }
111 |
112 | async function check_create_key(user) {
113 | let dbKey = await dbManager(user);
114 | if(('target' in dbKey) && (dbKey.target.result) &&
115 | (dbKey.target.result.user == user)) {
116 | return import_key(dbKey.target.result.key);
117 | }
118 | return window.crypto.subtle.generateKey(
119 | {
120 | name: "RSA-OAEP",
121 | modulusLength: 4096,
122 | publicExponent: new Uint8Array([1, 0, 1]),
123 | hash: "SHA-256",
124 | },
125 | true,
126 | ["encrypt", "decrypt"]
127 | ).then(function(key) {
128 | save_key(user,key);
129 | return key;
130 | });
131 | }
132 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | CVE Services Client Interface
8 |
9 |
13 |
17 |
20 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 | Alert
39 |
40 |
84 |
166 |
504 |
505 |
506 |
507 |
515 |
516 |
532 |
533 |
535 |
536 |
538 |
539 |
540 |
544 |
545 |
558 |
559 |
560 |
561 |
608 |
670 |
671 |
672 |
673 | Demo of CVE 5.0 service client
674 |
730 |
731 |
733 |
734 | Year:
739 |
740 |
741 |
744 |
745 |
746 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 | This website does NOT store any data or track usage. The code is freely available
759 | at GitHub
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
--------------------------------------------------------------------------------
/language-codes.json:
--------------------------------------------------------------------------------
1 | {"source": "https://datahub.io/core/language-codes/r/language-codes.json",
2 | "langs": [{"English": "Afar", "alpha2": "aa"},{"English": "Abkhazian", "alpha2": "ab"},{"English": "Avestan", "alpha2": "ae"},{"English": "Afrikaans", "alpha2": "af"},{"English": "Akan", "alpha2": "ak"},{"English": "Amharic", "alpha2": "am"},{"English": "Aragonese", "alpha2": "an"},{"English": "Arabic", "alpha2": "ar"},{"English": "Assamese", "alpha2": "as"},{"English": "Avaric", "alpha2": "av"},{"English": "Aymara", "alpha2": "ay"},{"English": "Azerbaijani", "alpha2": "az"},{"English": "Bashkir", "alpha2": "ba"},{"English": "Belarusian", "alpha2": "be"},{"English": "Bulgarian", "alpha2": "bg"},{"English": "Bihari languages", "alpha2": "bh"},{"English": "Bislama", "alpha2": "bi"},{"English": "Bambara", "alpha2": "bm"},{"English": "Bengali", "alpha2": "bn"},{"English": "Tibetan", "alpha2": "bo"},{"English": "Breton", "alpha2": "br"},{"English": "Bosnian", "alpha2": "bs"},{"English": "Catalan; Valencian", "alpha2": "ca"},{"English": "Chechen", "alpha2": "ce"},{"English": "Chamorro", "alpha2": "ch"},{"English": "Corsican", "alpha2": "co"},{"English": "Cree", "alpha2": "cr"},{"English": "Czech", "alpha2": "cs"},{"English": "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic", "alpha2": "cu"},{"English": "Chuvash", "alpha2": "cv"},{"English": "Welsh", "alpha2": "cy"},{"English": "Danish", "alpha2": "da"},{"English": "German", "alpha2": "de"},{"English": "Divehi; Dhivehi; Maldivian", "alpha2": "dv"},{"English": "Dzongkha", "alpha2": "dz"},{"English": "Ewe", "alpha2": "ee"},{"English": "Greek, Modern (1453-)", "alpha2": "el"},{"English": "English", "alpha2": "en"},{"English": "Esperanto", "alpha2": "eo"},{"English": "Spanish; Castilian", "alpha2": "es"},{"English": "Estonian", "alpha2": "et"},{"English": "Basque", "alpha2": "eu"},{"English": "Persian", "alpha2": "fa"},{"English": "Fulah", "alpha2": "ff"},{"English": "Finnish", "alpha2": "fi"},{"English": "Fijian", "alpha2": "fj"},{"English": "Faroese", "alpha2": "fo"},{"English": "French", "alpha2": "fr"},{"English": "Western Frisian", "alpha2": "fy"},{"English": "Irish", "alpha2": "ga"},{"English": "Gaelic; Scottish Gaelic", "alpha2": "gd"},{"English": "Galician", "alpha2": "gl"},{"English": "Guarani", "alpha2": "gn"},{"English": "Gujarati", "alpha2": "gu"},{"English": "Manx", "alpha2": "gv"},{"English": "Hausa", "alpha2": "ha"},{"English": "Hebrew", "alpha2": "he"},{"English": "Hindi", "alpha2": "hi"},{"English": "Hiri Motu", "alpha2": "ho"},{"English": "Croatian", "alpha2": "hr"},{"English": "Haitian; Haitian Creole", "alpha2": "ht"},{"English": "Hungarian", "alpha2": "hu"},{"English": "Armenian", "alpha2": "hy"},{"English": "Herero", "alpha2": "hz"},{"English": "Interlingua (International Auxiliary Language Association)", "alpha2": "ia"},{"English": "Indonesian", "alpha2": "id"},{"English": "Interlingue; Occidental", "alpha2": "ie"},{"English": "Igbo", "alpha2": "ig"},{"English": "Sichuan Yi; Nuosu", "alpha2": "ii"},{"English": "Inupiaq", "alpha2": "ik"},{"English": "Ido", "alpha2": "io"},{"English": "Icelandic", "alpha2": "is"},{"English": "Italian", "alpha2": "it"},{"English": "Inuktitut", "alpha2": "iu"},{"English": "Japanese", "alpha2": "ja"},{"English": "Javanese", "alpha2": "jv"},{"English": "Georgian", "alpha2": "ka"},{"English": "Kongo", "alpha2": "kg"},{"English": "Kikuyu; Gikuyu", "alpha2": "ki"},{"English": "Kuanyama; Kwanyama", "alpha2": "kj"},{"English": "Kazakh", "alpha2": "kk"},{"English": "Kalaallisut; Greenlandic", "alpha2": "kl"},{"English": "Central Khmer", "alpha2": "km"},{"English": "Kannada", "alpha2": "kn"},{"English": "Korean", "alpha2": "ko"},{"English": "Kanuri", "alpha2": "kr"},{"English": "Kashmiri", "alpha2": "ks"},{"English": "Kurdish", "alpha2": "ku"},{"English": "Komi", "alpha2": "kv"},{"English": "Cornish", "alpha2": "kw"},{"English": "Kirghiz; Kyrgyz", "alpha2": "ky"},{"English": "Latin", "alpha2": "la"},{"English": "Luxembourgish; Letzeburgesch", "alpha2": "lb"},{"English": "Ganda", "alpha2": "lg"},{"English": "Limburgan; Limburger; Limburgish", "alpha2": "li"},{"English": "Lingala", "alpha2": "ln"},{"English": "Lao", "alpha2": "lo"},{"English": "Lithuanian", "alpha2": "lt"},{"English": "Luba-Katanga", "alpha2": "lu"},{"English": "Latvian", "alpha2": "lv"},{"English": "Malagasy", "alpha2": "mg"},{"English": "Marshallese", "alpha2": "mh"},{"English": "Maori", "alpha2": "mi"},{"English": "Macedonian", "alpha2": "mk"},{"English": "Malayalam", "alpha2": "ml"},{"English": "Mongolian", "alpha2": "mn"},{"English": "Marathi", "alpha2": "mr"},{"English": "Malay", "alpha2": "ms"},{"English": "Maltese", "alpha2": "mt"},{"English": "Burmese", "alpha2": "my"},{"English": "Nauru", "alpha2": "na"},{"English": "Bokm\u00e5l, Norwegian; Norwegian Bokm\u00e5l", "alpha2": "nb"},{"English": "Ndebele, North; North Ndebele", "alpha2": "nd"},{"English": "Nepali", "alpha2": "ne"},{"English": "Ndonga", "alpha2": "ng"},{"English": "Dutch; Flemish", "alpha2": "nl"},{"English": "Norwegian Nynorsk; Nynorsk, Norwegian", "alpha2": "nn"},{"English": "Norwegian", "alpha2": "no"},{"English": "Ndebele, South; South Ndebele", "alpha2": "nr"},{"English": "Navajo; Navaho", "alpha2": "nv"},{"English": "Chichewa; Chewa; Nyanja", "alpha2": "ny"},{"English": "Occitan (post 1500)", "alpha2": "oc"},{"English": "Ojibwa", "alpha2": "oj"},{"English": "Oromo", "alpha2": "om"},{"English": "Oriya", "alpha2": "or"},{"English": "Ossetian; Ossetic", "alpha2": "os"},{"English": "Panjabi; Punjabi", "alpha2": "pa"},{"English": "Pali", "alpha2": "pi"},{"English": "Polish", "alpha2": "pl"},{"English": "Pushto; Pashto", "alpha2": "ps"},{"English": "Portuguese", "alpha2": "pt"},{"English": "Quechua", "alpha2": "qu"},{"English": "Romansh", "alpha2": "rm"},{"English": "Rundi", "alpha2": "rn"},{"English": "Romanian; Moldavian; Moldovan", "alpha2": "ro"},{"English": "Russian", "alpha2": "ru"},{"English": "Kinyarwanda", "alpha2": "rw"},{"English": "Sanskrit", "alpha2": "sa"},{"English": "Sardinian", "alpha2": "sc"},{"English": "Sindhi", "alpha2": "sd"},{"English": "Northern Sami", "alpha2": "se"},{"English": "Sango", "alpha2": "sg"},{"English": "Sinhala; Sinhalese", "alpha2": "si"},{"English": "Slovak", "alpha2": "sk"},{"English": "Slovenian", "alpha2": "sl"},{"English": "Samoan", "alpha2": "sm"},{"English": "Shona", "alpha2": "sn"},{"English": "Somali", "alpha2": "so"},{"English": "Albanian", "alpha2": "sq"},{"English": "Serbian", "alpha2": "sr"},{"English": "Swati", "alpha2": "ss"},{"English": "Sotho, Southern", "alpha2": "st"},{"English": "Sundanese", "alpha2": "su"},{"English": "Swedish", "alpha2": "sv"},{"English": "Swahili", "alpha2": "sw"},{"English": "Tamil", "alpha2": "ta"},{"English": "Telugu", "alpha2": "te"},{"English": "Tajik", "alpha2": "tg"},{"English": "Thai", "alpha2": "th"},{"English": "Tigrinya", "alpha2": "ti"},{"English": "Turkmen", "alpha2": "tk"},{"English": "Tagalog", "alpha2": "tl"},{"English": "Tswana", "alpha2": "tn"},{"English": "Tonga (Tonga Islands)", "alpha2": "to"},{"English": "Turkish", "alpha2": "tr"},{"English": "Tsonga", "alpha2": "ts"},{"English": "Tatar", "alpha2": "tt"},{"English": "Twi", "alpha2": "tw"},{"English": "Tahitian", "alpha2": "ty"},{"English": "Uighur; Uyghur", "alpha2": "ug"},{"English": "Ukrainian", "alpha2": "uk"},{"English": "Urdu", "alpha2": "ur"},{"English": "Uzbek", "alpha2": "uz"},{"English": "Venda", "alpha2": "ve"},{"English": "Vietnamese", "alpha2": "vi"},{"English": "Volap\u00fck", "alpha2": "vo"},{"English": "Walloon", "alpha2": "wa"},{"English": "Wolof", "alpha2": "wo"},{"English": "Xhosa", "alpha2": "xh"},{"English": "Yiddish", "alpha2": "yi"},{"English": "Yoruba", "alpha2": "yo"},{"English": "Zhuang; Chuang", "alpha2": "za"},{"English": "Chinese", "alpha2": "zh"},{"English": "Zulu", "alpha2": "zu"}]
3 | }
4 |
--------------------------------------------------------------------------------
/schemaToForm.js:
--------------------------------------------------------------------------------
1 | function schemaToForm(schemaUrl, elementId) {
2 | "use strict";
3 | if( !(this instanceof schemaToForm) ){
4 | return new schemaToForm(...arguments);
5 | }
6 | this._version = "1.0.9";
7 | let main = this;
8 | async function fetchObj(url) {
9 | try {
10 | const response = await fetch(url);
11 | return await response.json();
12 | } catch (error) {
13 | console.error('Error fetching schema:', error);
14 | return null;
15 | }
16 | }
17 | function populate(obj, base) {
18 | Object.keys(obj).forEach(function(field) {
19 | let bfield = field;
20 | if(base)
21 | bfield = base + "." + field;
22 | let el = document.querySelector("[data-path='" + bfield + "']");
23 | if(el) {
24 | if(el.querySelector("div") &&
25 | (!el.querySelector("div").checkVisibility())) {
26 | displayOnly(el.querySelector("legend"));
27 | }
28 | }
29 | if(typeof(obj[field]) == "object") {
30 | if(field.match(/^\d+$/)) {
31 | let count = parseInt(field) + 1;
32 | let sfield = bfield.replace(/\.\d+$/,'.0');
33 | let rcount = document.querySelectorAll("[data-path='" + sfield + "']").length;
34 |
35 | /* If the fields do not exist create them*/
36 | if(rcount > 0 && rcount < count) {
37 | const tel = document.querySelector("[data-path='" + sfield + "']").querySelector("legend > a");
38 | if(tel && tel.parentElement)
39 | cloner(tel.parentElement);
40 | }
41 | }
42 | return populate(obj[field], bfield);
43 | }
44 | if(el) {
45 | el.value = obj[field];
46 | if(el.style && el.style.border && el.style.border.indexOf("red") > -1) {
47 | el.style.border = "1px solid green";
48 | if(el.validity && el.validity.valid) {
49 | const sp = document.createElement('span');
50 | sp.innerHTML = " ✓ ";
51 | sp.style.color = "green";
52 | sp.setAttribute("data-valid",el.getAttribute("data-path"));
53 | el.after(sp);
54 | }
55 | }
56 | } else {
57 | console.error(obj, base, field);
58 | }
59 | });
60 | }
61 | function resolveRef(ref, prop, schema) {
62 | const path = ref.replace(/^#\/definitions\//, '').split('/');
63 | let resolved = schema.definitions;
64 | path.forEach(p => {
65 | if(p in resolved)
66 | resolved = resolved[p];
67 | else
68 | resolved = {};
69 | });
70 | let copyFields = ["examples","minItems","maxItems","allOf","anyOf"];
71 | copyFields.forEach(field => { if(prop && field in prop)
72 | resolved[prop] = field[prop] });
73 | if(resolved.$ref)
74 | return resolveRef(resolved.$ref, prop, schema);
75 | return resolved;
76 | }
77 | function elToField(el) {
78 | let elx;
79 | let eltype = "string";
80 | let elkey;
81 | let oldtype = "string";
82 | let tree = [];
83 | elx = el.parentElement;
84 | let cid = 0;
85 | while(elx) {
86 | if(elx.tagName == "FIELDSET" && elx.hasAttribute("data-cid")) {
87 | cid = parseInt(elx.getAttribute("data-cid"));
88 | }
89 | if(elx.tagName == "DIV" && elx.hasAttribute("data-type")) {
90 | eltype = elx.getAttribute("data-type");
91 | elkey = elx.getAttribute("data-key");
92 | if(eltype == "array") {
93 | if(oldtype == "object")
94 | tree.pop();
95 | tree.push(cid);
96 | tree.push(elkey);
97 | }
98 | if((eltype == "object") || ((eltype == "string" || eltype == "number" || eltype == "boolean" ) && elkey != '[]'))
99 | tree.push(elkey);
100 |
101 | oldtype = eltype;
102 | }
103 | elx = elx.parentElement;
104 | }
105 | /* Remove the last element if the path value is empty like a.b.c.d.0 is a string/enum/int
106 | and NOT an object or another array */
107 | if(tree[0] == "" && el.tagName != "FIELDSET")
108 | tree.shift();
109 | el.setAttribute("data-path", tree.reverse().join("."));
110 | }
111 | main.elToField = elToField;
112 | function removeRequired(el) {
113 | el.removeAttribute("required");
114 | el.removeAttribute("data-required");
115 | el.removeAttribute("style");
116 | }
117 | function makeRequired(el) {
118 | const allowed = ["INPUT","TEXTAREA","SELECT"];
119 | if(allowed.includes(el.tagName))
120 | el.setAttribute("required", true);
121 | el.setAttribute("data-required",true);
122 | el.style.border = "1px solid red";
123 | }
124 | function hideDecloners(el) {
125 | let els = el.querySelectorAll(":scope > fieldset > legend > a[data-decloner]");
126 | if(els.length == 1) {
127 | els[0].style.display = "";
128 | } else {
129 | for(let i=0; i < els.length - 1; i++)
130 | els[i].style.display = "none";
131 | els[els.length - 1].style.display = "";
132 | }
133 | }
134 |
135 | function decloner(el) {
136 | let es = el.parentElement.parentElement.querySelector(el.tagName).parentElement;
137 | if(el.querySelector("[data-hidder]") && (es.getAttribute("data-counter") == "0")) {
138 | el.parentElement.querySelector("div").style.display = "none";
139 | el.innerHTML = el.innerHTML.replace('[0]','[]');
140 | if(el.querySelector("[data-hidder]"))
141 | el.querySelector("[data-hidder]").remove();
142 | return;
143 | }
144 | if(es && es.hasAttribute("data-counter")) {
145 | let delid = es.getAttribute("data-counter");
146 | let er = el.parentElement.parentElement.querySelector("[data-cid='" + delid + "']");
147 | if(er) {
148 | let et = er.parentElement;
149 | er.remove();
150 | hideDecloners(et);
151 | es.setAttribute("data-counter", String(parseInt(delid) - 1));
152 | }
153 | }
154 | }
155 | function deleterButton(deleter) {
156 | if(!deleter) {
157 | /* Identify a new deleter button with a data-hidder attribute*/
158 | deleter = document.createElement('a');
159 | deleter.setAttribute('data-hidder', "1");
160 | }
161 | deleter.innerHTML = " ⊖ ";
162 | deleter.style.color = "#dc3545";
163 | deleter.style.cursor = "pointer";
164 | deleter.setAttribute("title","Delete/Remove this entry");
165 | deleter.addEventListener("click", function () {
166 | decloner(this.parentElement);
167 | });
168 | deleter.setAttribute('data-decloner', "1");
169 | return deleter;
170 | }
171 | function displayOnly(el) {
172 | el.parentElement.querySelectorAll("div").forEach(function(eldiv) {
173 | eldiv.style.display = "block";
174 | })
175 | el.innerHTML = el.innerHTML.replaceAll('[]','[0]');
176 | if(!el.querySelector("[data-hidder]")){
177 | el.appendChild(deleterButton());
178 | }
179 | }
180 | function cloner(el) {
181 | /* If the first div is invisible, this is a
182 | NOT required fieldset just display it and return */
183 | if((!el.hasAttribute("data-required")) && el.parentElement.querySelector("div").style.display == "none") {
184 | return displayOnly(el);
185 | }
186 | let cloned = el.parentElement.cloneNode(true);
187 | if(cloned.querySelector("[data-hidder]"))
188 | cloned.querySelector("[data-hidder]").remove();
189 | let i = parseInt(el.parentElement.getAttribute("data-counter") || "0");
190 | let elx = cloned.querySelector(el.tagName);
191 | if(elx) {
192 | elx.innerHTML = elx.innerHTML.replace(/\[(\d+)\]/, function() {
193 | return "[" + String(i + 1) + "]";
194 | });
195 | elx.parentElement.setAttribute("data-cid", String(i + 1));
196 | elx.parentElement.removeAttribute("data-counter");
197 | let ela = elx.querySelector('a');
198 | if(ela) {
199 | ela = deleterButton(ela);
200 | }
201 |
202 | }
203 | el.parentElement.setAttribute("data-counter", String(i + 1));
204 | el.parentElement.parentElement.appendChild(cloned);
205 | cloned.querySelectorAll('input,select:not([data-exclude])').forEach(elToField);
206 | hideDecloners(el.parentElement.parentElement);
207 | }
208 |
209 | function regexUpgrade(regex) {
210 | /*Upgrade regex that is invalid for v-mode to a compatible mode */
211 | try {
212 | const _ = new RegExp(regex,"v");
213 | return regex;
214 | } catch(err) {
215 | let nregex = regex;
216 | /* dash only in character classes otherwise but it in brackets escaped */
217 | const vInvalid = /([^a-zA-Z0-9\\])\-([^a-zA-Z0-9])/g;
218 |
219 | Array.from(new Set(regex.match(vInvalid))).forEach(function(bok) {
220 | nregex = nregex.replaceAll(bok,bok.replaceAll('-','[\\-]'));
221 | });
222 | try {
223 | new RegExp(nregex,"v");
224 | console.log("Replacing " + regex + " due to Error " + err +
225 | "Now upgraded to " + nregex);
226 | return nregex;
227 | } catch (err) {
228 | console.error("Cannot upgrade this " + regex + " due to Error " + err +
229 | "Now upgraded to " + nregex);
230 | return "";
231 | }
232 | }
233 | }
234 |
235 |
236 |
237 | function createInputFromProperty(key, property, required, schema) {
238 | const wrapper = document.createElement('div');
239 | if (property.$ref) {
240 | property = resolveRef(property.$ref, property, schema);
241 | }
242 | wrapper.setAttribute("data-key", key);
243 | wrapper.setAttribute("data-type", property.type);
244 | const label = document.createElement('label');
245 | label.setAttribute('for', key);
246 | label.textContent = property.title || key;
247 | wrapper.appendChild(label);
248 | wrapper.appendChild (document.createTextNode (" "));
249 | /* If anyof or allof is setup some form of this field(set) is required*/
250 | if(property.items)
251 | ["anyOf", "allOf", "oneOf"].forEach(yOf => {
252 | if(yOf in property.items) {
253 | required = true;
254 | if(!(yOf in property))
255 | property["validator"] = {}
256 | property["validator"][yOf] = property.items[yOf];
257 | }
258 | });
259 | let input;
260 | if (property.type === 'string') {
261 | input = document.createElement('input');
262 | input.setAttribute('type', property.format === 'email' ? 'email' : 'text');
263 | } else if (property.type === 'integer' || property.type === 'number') {
264 | input = document.createElement('input');
265 | input.setAttribute('type', 'number');
266 | } else if (property.type === 'boolean') {
267 | input = document.createElement('input');
268 | input.setAttribute('type', 'checkbox');
269 | } else if ((property.type === 'array') && (property.items)) {
270 | if (property.items.enum) {
271 | input = document.createElement('select');
272 | input.setAttribute('multiple', true);
273 | property.items.enum.forEach(value => input.appendChild(new Option(value,value)));
274 | } else {
275 | label.style.display = "none";
276 | const fieldset = document.createElement('fieldset');
277 | const legend = document.createElement('legend');
278 | if(required)
279 | legend.innerHTML = (property.title || key) + ' [0]' ;
280 | else
281 | legend.innerHTML = (property.title || key) + ' []' ;
282 | const adder = document.createElement('a');
283 | adder.style.color = "#007bff";
284 | adder.style.cursor = "pointer";
285 | adder.setAttribute("title","Add new entry for " + (property.title || key));
286 | adder.addEventListener("click", function () {
287 | cloner(this.parentElement);
288 | });
289 | adder.setAttribute('data-cloner', "1");
290 | adder.innerHTML = ' ⊕ ';
291 | fieldset.setAttribute("data-property", key);
292 | fieldset.setAttribute("data-counter", "0");
293 | fieldset.setAttribute("data-cid", "0");
294 | legend.appendChild(adder);
295 | fieldset.appendChild(legend);
296 | if(property.items.oneOf) {
297 | const selectEl = document.createElement('select');
298 | selectEl.setAttribute("data-exclude","oneOf");
299 | const classBase = label.textContent + "oneOf";
300 | selectEl.setAttribute("data-classBase", classBase);
301 | const created = {};
302 | property.items.oneOf.forEach((item,i) => {
303 | const className = classBase + String(i);
304 | if(item.required) {
305 | selectEl.appendChild(new Option("Valid Formats: " + String(i), className));
306 | item.required.forEach(subKey => {
307 | if(subKey in property.items.properties) {
308 | if (!(subKey in created)) {
309 | let subItem = property.items.properties[subKey];
310 | /* First set of inputs will be default required i == 0 */
311 | const subInput = createInputFromProperty(subKey, subItem, i < 1, schema);
312 | created[subKey] = subInput;
313 | }
314 | }
315 | created[subKey].querySelectorAll('input')
316 | .forEach(x => x.classList.add(classBase,className));
317 | });
318 | selectEl.addEventListener(
319 | 'change',
320 | function() {
321 | let classBase = this.getAttribute("data-classBase");
322 | document.querySelectorAll("." + classBase).forEach(removeRequired);
323 | let className = this.options[this.selectedIndex].value;
324 | document.querySelectorAll("." + className).forEach(makeRequired);
325 | },
326 | false
327 | );
328 | } else {
329 | selectEl.appendChild(new Option("Schema Formats: " + String(i), className));
330 | if(item.$ref)
331 | item = resolveRef(item.$ref, item, schema);
332 | let subKey = key + String(i);
333 | /* item if it got resolved form $ref may have "required" fields*/
334 | const subRequired = item.required && item.required.includes(subKey);
335 | created[subKey] = createInputFromProperty("", item, false, schema);
336 | created[subKey].classList.add(classBase,className);
337 | if(i > 0)
338 | created[subKey].style.display = "none";
339 | selectEl.addEventListener(
340 | 'change',
341 | function() {
342 | let classBase = this.getAttribute("data-classBase");
343 | document.querySelectorAll("." + classBase)
344 | .forEach( x => x.style.display = "none");
345 | let className = this.options[this.selectedIndex].value;
346 | document.querySelectorAll("." + className)
347 | .forEach(x => x.style.display = "block");
348 | },
349 | false
350 | );
351 |
352 | }
353 | });
354 | /* Now add all the inputs */
355 | Object.entries(created).forEach(function([_,x]) { fieldset.appendChild(x) });
356 | fieldset.prepend(selectEl);
357 | } else {
358 | let subItem;
359 | if(property.items.$ref) {
360 | const subProperty = resolveRef(property.items.$ref, property.items, schema);
361 | let subKey = property.items.$ref.split('/').pop();
362 | const subRequired = property.minItems && property.minItems > 0;
363 | subItem = createInputFromProperty(subKey, subProperty, subRequired, schema);
364 | } else {
365 | subItem = createInputFromProperty('[]',property.items, property.items.minItems && property.items.minItems > 0, schema);
366 | }
367 | fieldset.appendChild(subItem);
368 | }
369 | if (required)
370 | makeRequired(fieldset);
371 | wrapper.appendChild(fieldset);
372 | return wrapper; // return early because object fields are handled recursively
373 | }
374 | } else if (property.type === 'object') {
375 | label.style.display = "none";
376 | // Recursively create form elements for nested objects
377 | const fieldset = document.createElement('fieldset');
378 | const legend = document.createElement('legend');
379 | legend.textContent = property.title || key;
380 | fieldset.appendChild(legend);
381 | if(property.properties) {
382 | Object.keys(property.properties).forEach(function(subKey) {
383 | let subProperty = property.properties[subKey];
384 | if(subProperty.$ref) {
385 | subProperty = resolveRef(subProperty.$ref, subProperty, schema);
386 | }
387 | const subRequired = property.required && property.required.includes(subKey);
388 | const subInput = createInputFromProperty(subKey, subProperty, subRequired, schema);
389 | fieldset.appendChild(subInput);
390 | });
391 | if (required) {
392 | makeRequired(fieldset);
393 | }
394 | wrapper.appendChild(fieldset);
395 | }
396 | return wrapper; // return early because object fields are handled recursively
397 | } else {
398 | input = document.createElement('input');
399 | input.setAttribute('type', 'text'); // Fallback for unsupported types
400 | }
401 | input.setAttribute('name', key);
402 | if (property.enum) {
403 | if(property.enum.length > 1) {
404 | input = document.createElement('select');
405 | input.appendChild(new Option("Select..",""));
406 | property.enum.forEach(value => input.appendChild(new Option(value,value)));
407 | } else {
408 | input.setAttribute('readonly',true);
409 | input.value = property.enum[0];
410 | input.style.border = "1px solid #333";
411 | input.style.background = "#eee";
412 | }
413 | }
414 | if (required)
415 | makeRequired(input);
416 | if(property.pattern && regexUpgrade(property.pattern))
417 | input.setAttribute("pattern", regexUpgrade(property.pattern));
418 | if(property.description)
419 | input.setAttribute("title", property.description);
420 | wrapper.appendChild(input);
421 | if(property.examples) {
422 | let example = document.createElement('select');
423 | example.setAttribute("data-exclude","example");
424 | example.appendChild(new Option("Example entries:",""));
425 | property.examples.forEach(ex => example.appendChild(new Option(ex,ex)));
426 | example.style.marginLeft = "0.2em";
427 | example.setAttribute("onchange","exampleFill(this)");
428 | wrapper.appendChild(example);
429 | }
430 | return wrapper;
431 | }
432 | function exampleFill(el) {
433 | if(el.value)
434 | el.previousElementSibling.value = el.value;
435 | }
436 | function createFormFromSchema(schema, parentElement) {
437 | const form = document.createElement('div');
438 | form.setAttribute('id', schema.title ? schema.title.toLowerCase().replace(/\s+/g, '-') + '-form' : 'dynamic-form');
439 | if(schema.oneOf) {
440 | const selectEl = document.createElement('select');
441 | selectEl.setAttribute("data-exclude","oneOf");
442 | selectEl.addEventListener(
443 | 'change',
444 | function() {
445 | let show = document.getElementById(this.options[this.selectedIndex].value);
446 | if(show) {
447 | parentElement.querySelectorAll(".selectEl")
448 | .forEach( x => x.style.display = "none");
449 | show.style.display = "block";
450 | }
451 | },
452 | false
453 | );
454 | const definitions = schema.definitions;
455 | schema.oneOf.forEach((schema,i) => {
456 | /* If definitions exists copy them over to schema subschema*/
457 | if(definitions)
458 | schema.definitions = definitions;
459 | const oneElement = document.createElement('div');
460 | oneElement.id = schema.title || ('selectEl' + String(i));
461 | if(i > 0)
462 | oneElement.style.display = "none";
463 | oneElement.className = "selectEl";
464 | parentElement.appendChild(oneElement);
465 | createFormFromSchema(schema, oneElement);
466 | selectEl.appendChild(new Option(oneElement.id, oneElement.id));
467 | });
468 | parentElement.prepend(selectEl);
469 | return;
470 | }
471 | if(schema.properties) {
472 | Object.keys(schema.properties).forEach(key => {
473 | let property = schema.properties[key];
474 |
475 | // Resolve $ref if it exists
476 | if (property.$ref) {
477 | property = resolveRef(property.$ref, property, schema);
478 | }
479 |
480 | const required = schema.required && schema.required.includes(key);
481 | const inputElement = createInputFromProperty(key, property, required, schema);
482 | form.appendChild(inputElement);
483 | });
484 | }
485 | parentElement.appendChild(form);
486 | /* Add field designation in Object-Oriented form */
487 | parentElement.querySelectorAll('input,select:not([data-exclude])').forEach(elToField);
488 | /* Add field desgination i OO form to fieldset that are arrays */
489 | parentElement.querySelectorAll("[data-counter='0']").forEach(elToField);
490 | /* Ensure not required fieldset are added only as needed*/
491 | parentElement.querySelectorAll('fieldset:not([data-required])')
492 | .forEach(el => el.querySelector('div').style.display = "none");
493 |
494 | }
495 | async function initializeForm(schemaUrl, elementId) {
496 | const schema = await fetchObj(schemaUrl);
497 | const dElement = document.getElementById(elementId);
498 | if (schema && dElement) {
499 | main.dElement = dElement;
500 | createFormFromSchema(schema, dElement);
501 | } else {
502 | document.getElementById(elementId).textContent = 'Failed to load schema.';
503 | }
504 | }
505 | function toData() {
506 | let fobj = {};
507 | main.dElement.querySelectorAll('input,select[data-path]:not([data-exclude])').forEach( function(el) {
508 | if(!el.checkVisibility())
509 | return;
510 | let val = el.value;
511 | if(el.type == "checkbox") {
512 | if(el.checked)
513 | val = true;
514 | else
515 | val = false;
516 | }
517 | /* If val is empty or set to be False for a not required element */
518 | if(!val)
519 | if(!el.hasAttribute("data-required"))
520 | return;
521 | let x = fobj;
522 | let prop = el.getAttribute("data-path");
523 | console.log(x);
524 | if(!prop)
525 | return;
526 | let props = prop.split(".");
527 | if(!props.length)
528 | return;
529 | let fprop = props.pop();
530 | for(var i=0; i x.style.display = "none");
562 | }
563 | initializeForm(schemaUrl, elementId);
564 | main.populate = populate;
565 | main.toData = toData;
566 | return main;
567 | }
568 |
--------------------------------------------------------------------------------
/sweetalert2/index.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CERTCC/cveClient/23eca2298a3a429e5e61d951450834648de3fc38/sweetalert2/index.html
--------------------------------------------------------------------------------
|