nskd-lbr 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -86,7 +86,8 @@ new NskdLbr(options)
86
86
  | `debug` | boolean | `false` | Enable debug logging |
87
87
  | `timeout` | number | `10000` | Request timeout in milliseconds |
88
88
  | `strictCheck` | boolean | `true` | Validate local data against API response |
89
- | `onnskdLbrLog` | function | `null` | Custom logging function |
89
+ | `useLegacyAPI` | boolean | `false` | Whether to use the legacy API format (nickname field or not) |
90
+ | `onLog` | function | `null` | Custom logging function |
90
91
 
91
92
  ### Methods
92
93
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nskd-lbr",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A JavaScript library for working with NoSkid certificates.",
5
5
  "main": "src/nskd-lbr.js",
6
6
  "scripts": {
package/src/nskd-lbr.js CHANGED
@@ -1,13 +1,15 @@
1
1
  /**
2
2
  * NoSkid Certificate Library
3
3
  * A JavaScript library for working with NoSkid certificates
4
- *
4
+ *
5
5
  * @version 1.0.0
6
6
  * @author Douxx <douxx@douxx.tech>
7
7
  * @param {string} [options.apiUrl='https://check.noskid.today/'] - Logs debug messages to console
8
8
  * @param {boolean} [options.debug=false] - Logs debug messages to console
9
9
  * @param {boolean} [options.strictCheck=true] - Whether to validate local data against API response
10
10
  * @param {integer} [options.timeout=10000] - API request timeout in milliseconds
11
+ * @param {boolean} [options.useLegacyAPI=false] - Whether to use the legacy API format
12
+ *
11
13
  * @param {function} [options.onLog=null] - Whether to validate local data against API response
12
14
  */
13
15
 
@@ -18,6 +20,7 @@ class NskdLbr {
18
20
  this.timeout = options.timeout || 10000;
19
21
  this.strictCheck = options.strictCheck !== undefined ? options.strictCheck : true;
20
22
  this.onLog = options.onLog || null;
23
+ this.useLegacyAPI = options.useLegacyAPI || false;
21
24
  this.certificateData = null;
22
25
  this.verificationKey = null;
23
26
  this.localData = null;
@@ -41,10 +44,10 @@ class NskdLbr {
41
44
  console.warn(prefix, message);
42
45
  break;
43
46
  case 'success':
44
- console.nskdLbrLog(`%c${prefix} ${message}`, 'color: green');
47
+ console.log(`%c${prefix} ${message}`, 'color: green');
45
48
  break;
46
49
  default:
47
- console.nskdLbrLog(prefix, message);
50
+ console.log(prefix, message);
48
51
  }
49
52
  }
50
53
 
@@ -146,8 +149,6 @@ class NskdLbr {
146
149
  };
147
150
  }
148
151
 
149
-
150
-
151
152
  /**
152
153
  * Check if the certificate is valid
153
154
  * @returns {boolean} True if certificate is valid
@@ -166,10 +167,12 @@ class NskdLbr {
166
167
  }
167
168
 
168
169
  const data = this.certificateData;
170
+ const username = this.useLegacyAPI ? data.username : data.nickname || data.username;
171
+
169
172
  return `
170
173
  Certificate Details:
171
174
  - Certificate #: ${data.certificate_number}
172
- - Username: ${data.username}
175
+ - Username: ${username}
173
176
  - Percentage: ${data.percentage}%
174
177
  - Creation Date: ${data.creationDate}
175
178
  - Country: ${data.country} (${data.countryCode})
@@ -248,7 +251,6 @@ Certificate Details:
248
251
  }
249
252
  }
250
253
  }
251
-
252
254
  pos += 8 + length + 4;
253
255
  }
254
256
 
@@ -349,7 +351,9 @@ Certificate Details:
349
351
 
350
352
  // Compare local data with API data if available and strictCheck is enabled
351
353
  if (this.localData && this.strictCheck) {
352
- const validationResult = this.compareData(this.localData, apiData.data);
354
+ const apiUsername = this.useLegacyAPI ? apiData.data.username : (apiData.data.nickname || apiData.data.username);
355
+ const validationResult = this.compareData(this.localData, { ...apiData.data, username: apiUsername });
356
+
353
357
  if (!validationResult.valid) {
354
358
  this.isValid = false;
355
359
  this.nskdLbrLog('Certificate data mismatch!', 'error');
@@ -422,4 +426,4 @@ if (typeof module !== 'undefined' && module.exports) {
422
426
  module.exports = NskdLbr;
423
427
  } else {
424
428
  window.NskdLbr = NskdLbr;
425
- }
429
+ }
@@ -1,8 +1,8 @@
1
- class NskdLbr{constructor(t={}){this.apiUrl=t.apiUrl||"https://check.noskid.today/",this.debug=t.debug||!1,this.timeout=t.timeout||1e4,this.strictCheck=t.strictCheck!==void 0?t.strictCheck:!0,this.onLog=t.onLog||null,this.certificateData=null,this.verificationKey=null,this.localData=null,this.isValid=!1}nskdLbrLog(t,e="info"){if(this.debug){const i=`[${new Date().toLocaleTimeString()}] NoSkid:`;switch(e){case"error":console.error(i,t);break;case"warning":console.warn(i,t);break;case"success":console.nskdLbrLog(`%c${i} ${t}`,"color: green");break;default:console.nskdLbrLog(i,t)}}this.onLog&&typeof this.onLog=="function"&&this.onLog(t,e)}async loadFromFile(t){try{if(this.nskdLbrLog("Starting certificate verification process...","info"),!t)throw new Error("No file provided");if(!t.name.toLowerCase().endsWith(".png"))throw new Error("File must be a PNG image");this.nskdLbrLog(`Processing certificate file: ${t.name}`,"info");const e=await this.readFileAsArrayBuffer(t),r=await this.extractTextFromPng(e);if(!r)throw new Error("Could not extract verification data from file");if(this.verificationKey=this.extractVerificationKey(r),!this.verificationKey)throw new Error("No valid verification key found in certificate");return this.nskdLbrLog("Successfully extracted verification key","success"),this.localData=this.extractLocalData(r),this.localData&&(this.nskdLbrLog("Local certificate data extracted:","info"),this.nskdLbrLog(`Username: ${this.localData.username}`,"info"),this.nskdLbrLog(`Creation Date: ${this.localData.creationDate}`,"info")),await this.verifyWithAPI()}catch(e){throw this.nskdLbrLog(`Error loading certificate: ${e.message}`,"error"),e}}async verifyWithKey(t){try{if(!t||typeof t!="string")throw new Error("Invalid verification key provided");if(!/^[a-f0-9]{64}$/i.test(t))throw new Error("Verification key must be a 64-character hexadecimal string");return this.verificationKey=t.toLowerCase(),this.nskdLbrLog(`Verifying certificate with key: ${this.verificationKey.substring(0,16)}...`,"info"),await this.verifyWithAPI()}catch(e){throw this.nskdLbrLog(`Error verifying certificate: ${e.message}`,"error"),e}}getCertificateData(){return this.certificateData}isValidCertificate(){return this.isValid}getFormattedDetails(){if(!this.certificateData)return"No certificate data available";const t=this.certificateData;return`
1
+ class NskdLbr{constructor(t={}){this.apiUrl=t.apiUrl||"https://check.noskid.today/",this.debug=t.debug||!1,this.timeout=t.timeout||1e4,this.strictCheck=void 0===t.strictCheck||t.strictCheck,this.onLog=t.onLog||null,this.useLegacyAPI=t.useLegacyAPI||!1,this.certificateData=null,this.verificationKey=null,this.localData=null,this.isValid=!1}nskdLbrLog(t,e="info"){if(this.debug){var r=`[${(new Date).toLocaleTimeString()}] NoSkid:`;switch(e){case"error":console.error(r,t);break;case"warning":console.warn(r,t);break;case"success":console.log(`%c${r} `+t,"color: green");break;default:console.log(r,t)}}this.onLog&&"function"==typeof this.onLog&&this.onLog(t,e)}async loadFromFile(t){try{if(this.nskdLbrLog("Starting certificate verification process...","info"),!t)throw new Error("No file provided");if(!t.name.toLowerCase().endsWith(".png"))throw new Error("File must be a PNG image");this.nskdLbrLog("Processing certificate file: "+t.name,"info");var e=await this.readFileAsArrayBuffer(t),r=await this.extractTextFromPng(e);if(!r)throw new Error("Could not extract verification data from file");if(this.verificationKey=this.extractVerificationKey(r),this.verificationKey)return this.nskdLbrLog("Successfully extracted verification key","success"),this.localData=this.extractLocalData(r),this.localData&&(this.nskdLbrLog("Local certificate data extracted:","info"),this.nskdLbrLog("Username: "+this.localData.username,"info"),this.nskdLbrLog("Creation Date: "+this.localData.creationDate,"info")),await this.verifyWithAPI();throw new Error("No valid verification key found in certificate")}catch(t){throw this.nskdLbrLog("Error loading certificate: "+t.message,"error"),t}}async verifyWithKey(t){try{if(!t||"string"!=typeof t)throw new Error("Invalid verification key provided");if(/^[a-f0-9]{64}$/i.test(t))return this.verificationKey=t.toLowerCase(),this.nskdLbrLog(`Verifying certificate with key: ${this.verificationKey.substring(0,16)}...`,"info"),await this.verifyWithAPI();throw new Error("Verification key must be a 64-character hexadecimal string")}catch(t){throw this.nskdLbrLog("Error verifying certificate: "+t.message,"error"),t}}getCertificateData(){return this.certificateData?{...this.certificateData,key:this.verificationKey,localUsername:this.localData?this.localData.username:null,localCreationDate:this.localData?this.localData.creationDate:null}:null}isValidCertificate(){return this.isValid}getFormattedDetails(){var t,e;return this.certificateData?(t=this.certificateData,e=!this.useLegacyAPI&&t.nickname||t.username,`
2
2
  Certificate Details:
3
3
  - Certificate #: ${t.certificate_number}
4
- - Username: ${t.username}
4
+ - Username: ${e}
5
5
  - Percentage: ${t.percentage}%
6
6
  - Creation Date: ${t.creationDate}
7
7
  - Country: ${t.country} (${t.countryCode})
8
- `.trim()}reset(){this.certificateData=null,this.verificationKey=null,this.localData=null,this.isValid=!1,this.nskdLbrLog("Certificate data reset","info")}readFileAsArrayBuffer(t){return new Promise((e,r)=>{const i=new FileReader;i.onload=a=>e(a.target.result),i.onerror=()=>r(new Error("Error reading file")),i.readAsArrayBuffer(t)})}async extractTextFromPng(t){try{const e=new Uint8Array(t);if(!(e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71))throw new Error("Not a valid PNG file");let r=8,i=null;for(;r<e.length-12;){const a=e[r]<<24|e[r+1]<<16|e[r+2]<<8|e[r+3];if(String.fromCharCode(e[r+4],e[r+5],e[r+6],e[r+7])==="tEXt"){const l=e.slice(r+8,r+8+a),s=new TextDecoder("utf-8").decode(l),o=s.indexOf("\0");if(o!==-1){const n=s.substring(0,o),d=s.substring(o+1);if(n==="noskid-key"){i=d;break}}}r+=8+a+4}return i?(this.nskdLbrLog("Certificate data extracted successfully from PNG","success"),i):(this.nskdLbrLog("No 'noskid-key' text chunk found in PNG","error"),null)}catch(e){return this.nskdLbrLog(`Error extracting text from PNG: ${e.message}`,"error"),null}}extractVerificationKey(t){try{const e=/-*BEGIN NOSKID KEY-*\s*([a-f0-9]{64})/i,r=t.match(e);return r?r[1].toLowerCase():null}catch(e){return this.nskdLbrLog(`Error extracting verification key: ${e.message}`,"error"),null}}extractLocalData(t){try{const e=/-----BEGIN NOSKID KEY-----\s*([a-f0-9]+)\s*([A-Za-z0-9+/=]+)\s*([A-Za-z0-9+/=]+)\s*-----END NOSKID KEY-----/,r=t.match(e);if(!r)return null;const i=r[2],c=atob(i.replace(/=/g,"")).match(/CERT-\d+-(.+)/),l=c?c[1]:null,s=r[3],n=atob(s.replace(/=/g,"")).match(/CREATED-(.+)/),d=n?n[1]:null;return{username:l,creationDate:d}}catch(e){return this.nskdLbrLog(`Error extracting local data: ${e.message}`,"error"),null}}async verifyWithAPI(){try{this.nskdLbrLog("Verifying certificate with server...","info");const t=new AbortController,e=setTimeout(()=>t.abort(),this.timeout),r=await fetch(`${this.apiUrl}?key=${encodeURIComponent(this.verificationKey)}`,{signal:t.signal,headers:{"User-Agent":"NskdLbr/1.0.0"}});if(clearTimeout(e),!r.ok)throw new Error(`HTTP ${r.status}: ${r.statusText}`);const i=await r.json();if(!i.success)return this.isValid=!1,this.nskdLbrLog(`Certificate verification failed: ${i.message}`,"error"),{valid:!1,message:i.message,cached:i.cached||!1};if(this.localData&&this.strictCheck){const a=this.compareData(this.localData,i.data);if(!a.valid)return this.isValid=!1,this.nskdLbrLog("Certificate data mismatch!","error"),this.nskdLbrLog(`Mismatch reason: ${a.reason}`,"error"),this.nskdLbrLog("Note: Strict checking is enabled. Set strictCheck to false to skip local data validation.","warning"),{valid:!1,message:`Data mismatch: ${a.reason}`,cached:i.cached||!1,strictCheck:!0};this.nskdLbrLog("Local data validation passed","success")}else this.localData&&!this.strictCheck&&this.nskdLbrLog("Strict checking disabled - skipping local data validation","warning");return this.isValid=!0,this.certificateData=i.data,this.nskdLbrLog("Certificate is VALID!","success"),{valid:!0,message:"Certificate verified successfully",data:i.data,cached:i.cached||!1,strictCheck:this.strictCheck}}catch(t){throw t.name==="AbortError"?new Error("Request timeout - server took too long to respond"):new Error(`API verification failed: ${t.message}`)}}compareData(t,e){if(!t||!e)return{valid:!1,reason:"Missing data for comparison"};if(t.username!==e.username)return{valid:!1,reason:`Username mismatch: Local=${t.username}, API=${e.username}`};const r=t.creationDate.substring(0,16),i=e.creationDate.substring(0,16);return r!==i?{valid:!1,reason:`Creation date mismatch: Local=${r}, API=${i}`}:{valid:!0}}}typeof module<"u"&&module.exports?module.exports=NskdLbr:window.NskdLbr=NskdLbr;
8
+ `.trim()):"No certificate data available"}reset(){this.certificateData=null,this.verificationKey=null,this.localData=null,this.isValid=!1,this.nskdLbrLog("Certificate data reset","info")}readFileAsArrayBuffer(a){return new Promise((e,t)=>{var r=new FileReader;r.onload=t=>e(t.target.result),r.onerror=()=>t(new Error("Error reading file")),r.readAsArrayBuffer(a)})}async extractTextFromPng(r){try{var a=new Uint8Array(r);if(137!==a[0]||80!==a[1]||78!==a[2]||71!==a[3])throw new Error("Not a valid PNG file");let t=8,e=null;for(;t<a.length-12;){var i=a[t]<<24|a[t+1]<<16|a[t+2]<<8|a[t+3];if("tEXt"===String.fromCharCode(a[t+4],a[t+5],a[t+6],a[t+7])){var s=a.slice(t+8,t+8+i),o=new TextDecoder("utf-8").decode(s),n=o.indexOf("\0");if(-1!==n){var c=o.substring(0,n),l=o.substring(n+1);if("noskid-key"===c){e=l;break}}}t+=8+i+4}return e?(this.nskdLbrLog("Certificate data extracted successfully from PNG","success"),e):(this.nskdLbrLog("No 'noskid-key' text chunk found in PNG","error"),null)}catch(t){return this.nskdLbrLog("Error extracting text from PNG: "+t.message,"error"),null}}extractVerificationKey(t){try{var e=/-*BEGIN NOSKID KEY-*\s*([a-f0-9]{64})/i,r=t.match(e);return r?r[1].toLowerCase():null}catch(t){return this.nskdLbrLog("Error extracting verification key: "+t.message,"error"),null}}extractLocalData(t){try{var e,r,a,i,s,o=/-----BEGIN NOSKID KEY-----\s*([a-f0-9]+)\s*([A-Za-z0-9+/=]+)\s*([A-Za-z0-9+/=]+)\s*-----END NOSKID KEY-----/,n=t.match(o);return n?(e=n[2],a=(r=atob(e.replace(/=/g,"")).match(/CERT-\d+-(.+)/))?r[1]:null,i=n[3],{username:a,creationDate:(s=atob(i.replace(/=/g,"")).match(/CREATED-(.+)/))?s[1]:null}):null}catch(t){return this.nskdLbrLog("Error extracting local data: "+t.message,"error"),null}}async verifyWithAPI(){try{this.nskdLbrLog("Verifying certificate with server...","info");let t=new AbortController;var e=setTimeout(()=>t.abort(),this.timeout),r=await fetch(this.apiUrl+"?key="+encodeURIComponent(this.verificationKey),{signal:t.signal,headers:{"User-Agent":"NskdLbr/1.0.0"}});if(clearTimeout(e),!r.ok)throw new Error(`HTTP ${r.status}: `+r.statusText);var a=await r.json();if(!a.success)return this.isValid=!1,this.nskdLbrLog("Certificate verification failed: "+a.message,"error"),{valid:!1,message:a.message,cached:a.cached||!1};if(this.localData&&this.strictCheck){var i=!this.useLegacyAPI&&a.data.nickname||a.data.username,s=this.compareData(this.localData,{...a.data,username:i});if(!s.valid)return this.isValid=!1,this.nskdLbrLog("Certificate data mismatch!","error"),this.nskdLbrLog("Mismatch reason: "+s.reason,"error"),this.nskdLbrLog("Note: Strict checking is enabled. Set strictCheck to false to skip local data validation.","warning"),{valid:!1,message:"Data mismatch: "+s.reason,cached:a.cached||!1,strictCheck:!0};this.nskdLbrLog("Local data validation passed","success")}else this.localData&&!this.strictCheck&&this.nskdLbrLog("Strict checking disabled - skipping local data validation","warning");return this.isValid=!0,this.certificateData=a.data,this.nskdLbrLog("Certificate is VALID!","success"),{valid:!0,message:"Certificate verified successfully",data:a.data,cached:a.cached||!1,strictCheck:this.strictCheck}}catch(t){if("AbortError"===t.name)throw new Error("Request timeout - server took too long to respond");throw new Error("API verification failed: "+t.message)}}compareData(t,e){return t&&e?t.username!==e.username?{valid:!1,reason:`Username mismatch: Local=${t.username}, API=`+e.username}:(t=t.creationDate.substring(0,16))!==(e=e.creationDate.substring(0,16))?{valid:!1,reason:`Creation date mismatch: Local=${t}, API=`+e}:{valid:!0}:{valid:!1,reason:"Missing data for comparison"}}}"undefined"!=typeof module&&module.exports?module.exports=NskdLbr:window.NskdLbr=NskdLbr;