nskd-lbr 1.0.3 → 1.1.0
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 +407 -79
- package/package.json +1 -1
- package/src/login.svg +1 -0
- package/src/nskd-lbr.js +767 -5
- package/src/nskd-lbr.min.js +443 -7
- package/src/t.html +65 -0
package/README.md
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
# NoSkid Certificate Library
|
|
2
2
|
|
|
3
|
-
A JavaScript library for
|
|
3
|
+
A modern JavaScript library for verifying NoSkid certificates and implementing certificate-based authentication.
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|
|
7
7
|
- [Installation](#installation)
|
|
8
|
-
- [
|
|
9
|
-
- [
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [Constructor Options](#constructor-options)
|
|
10
|
+
- [Methods](#methods)
|
|
11
|
+
- [Login with NoSkid](#login-with-noskid)
|
|
12
|
+
- [Response Objects](#response-objects)
|
|
10
13
|
- [Examples](#examples)
|
|
11
|
-
- [Configuration](#configuration)
|
|
12
14
|
- [Error Handling](#error-handling)
|
|
15
|
+
- [Browser Support](#browser-support)
|
|
13
16
|
- [Contributing](#contributing)
|
|
14
17
|
- [License](#license)
|
|
15
18
|
|
|
16
19
|
## Installation
|
|
17
20
|
|
|
18
|
-
### Browser
|
|
21
|
+
### Browser (CDN)
|
|
19
22
|
|
|
20
23
|
```html
|
|
21
24
|
<script src="https://lbr.noskid.today"></script>
|
|
@@ -31,137 +34,462 @@ npm install nskd-lbr
|
|
|
31
34
|
const NskdLbr = require('nskd-lbr');
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
### Basic Usage
|
|
37
|
+
## Quick Start
|
|
37
38
|
|
|
38
39
|
```js
|
|
39
40
|
// Initialize the library
|
|
40
|
-
const
|
|
41
|
+
const noskid = new NskdLbr(); //eventually specify parameters, well let the default ones here
|
|
41
42
|
|
|
42
|
-
// Verify a certificate from
|
|
43
|
+
// Verify a certificate from file upload
|
|
43
44
|
const fileInput = document.getElementById('certificate-file');
|
|
44
45
|
fileInput.addEventListener('change', async (event) => {
|
|
45
46
|
try {
|
|
46
|
-
const result = await
|
|
47
|
+
const result = await noskid.loadFromFile(event.target.files[0]);
|
|
48
|
+
console.log('Verification result:', result);
|
|
49
|
+
|
|
47
50
|
if (result.valid) {
|
|
48
|
-
console.log(
|
|
49
|
-
console.log(nskd.getFormattedDetails());
|
|
50
|
-
} else {
|
|
51
|
-
console.log('Certificate is invalid:', result.message);
|
|
51
|
+
console.log(noskid.getFormattedDetails());
|
|
52
52
|
}
|
|
53
53
|
} catch (error) {
|
|
54
54
|
console.error('Error:', error.message);
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
|
+
```
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
59
|
+
## Constructor Options
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
const noskid = new NskdLbr({
|
|
63
|
+
// Core options
|
|
64
|
+
apiUrl: 'https://check.noskid.today/', // Verification API endpoint
|
|
65
|
+
debug: false, // Enable debug logging
|
|
66
|
+
timeout: 10000, // Request timeout (ms)
|
|
67
|
+
strictCheck: true, // Validate local vs API data
|
|
68
|
+
useLegacyAPI: false, // Use legacy API format
|
|
69
|
+
|
|
70
|
+
// Login feature options
|
|
71
|
+
loginEndpoint: '', // Login API endpoint
|
|
72
|
+
onLoginSuccess: null, // Success callback function
|
|
73
|
+
onLoginFail: null, // Failure callback function
|
|
74
|
+
|
|
75
|
+
// Logging
|
|
76
|
+
onLog: null // Custom logging function
|
|
77
|
+
});
|
|
71
78
|
```
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
### Option Details
|
|
81
|
+
|
|
82
|
+
| Option | Type | Default | Description |
|
|
83
|
+
|--------|------|---------|-------------|
|
|
84
|
+
| `apiUrl` | `string` | `'https://check.noskid.today/'` | NoSkid verification API endpoint |
|
|
85
|
+
| `debug` | `boolean` | `false` | Enable console debug messages |
|
|
86
|
+
| `timeout` | `number` | `10000` | API request timeout in milliseconds |
|
|
87
|
+
| `strictCheck` | `boolean` | `true` | Compare local certificate data with API response |
|
|
88
|
+
| `useLegacyAPI` | `boolean` | `false` | Use legacy API format (affects username/nickname field) |
|
|
89
|
+
| `loginEndpoint` | `string` | `''` | Login API endpoint (required for login feature) |
|
|
90
|
+
| `onLoginSuccess` | `function` | `null` | `(result, certData) => {}` - Called on successful login |
|
|
91
|
+
| `onLoginFail` | `function` | `null` | `(error, certData) => {}` - Called on failed login |
|
|
92
|
+
| `onLog` | `function` | `null` | `(message, level) => {}` - Custom logging function |
|
|
93
|
+
|
|
94
|
+
## Methods
|
|
95
|
+
|
|
96
|
+
### Certificate Verification
|
|
97
|
+
|
|
98
|
+
#### `loadFromFile(file)`
|
|
99
|
+
|
|
100
|
+
Load and verify a certificate from a PNG file.'
|
|
74
101
|
|
|
75
|
-
|
|
102
|
+
**Parameters:**
|
|
103
|
+
- `file` (`File`) - PNG certificate file from file input
|
|
76
104
|
|
|
77
|
-
|
|
78
|
-
|
|
105
|
+
**Returns:** `Promise<VerificationResult>`
|
|
106
|
+
|
|
107
|
+
**Example:**
|
|
108
|
+
```js
|
|
109
|
+
const result = await noskid.loadFromFile(file);
|
|
110
|
+
// Returns: { valid: true, message: "Certificate verified successfully", data: {...}, cached: false }
|
|
79
111
|
```
|
|
80
112
|
|
|
81
|
-
|
|
113
|
+
#### `verifyWithKey(key)`
|
|
82
114
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
115
|
+
Verify a certificate using a verification key directly.
|
|
116
|
+
|
|
117
|
+
**Parameters:**
|
|
118
|
+
- `key` (`string`) - 64-character hexadecimal verification key
|
|
119
|
+
|
|
120
|
+
**Returns:** `Promise<VerificationResult>`
|
|
121
|
+
|
|
122
|
+
**Example:**
|
|
123
|
+
```js
|
|
124
|
+
const result = await noskid.verifyWithKey('a1b2c3d4e5f6789...');
|
|
125
|
+
// Returns: { valid: true, message: "Certificate verified successfully", data: {...}, cached: false }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Data Access
|
|
129
|
+
|
|
130
|
+
#### `getCertificateData()`
|
|
131
|
+
|
|
132
|
+
Get the current certificate data after successful verification.
|
|
133
|
+
|
|
134
|
+
**Returns:** `CertificateData | null`
|
|
135
|
+
|
|
136
|
+
**Example:**
|
|
137
|
+
```js
|
|
138
|
+
const certData = noskid.getCertificateData();
|
|
139
|
+
// Returns: { certificate_number: "12345", username: "john_doe", percentage: 95, ... }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `isValidCertificate()`
|
|
143
|
+
|
|
144
|
+
Check if the currently loaded certificate is valid.
|
|
145
|
+
|
|
146
|
+
**Returns:** `boolean`
|
|
147
|
+
|
|
148
|
+
#### `getFormattedDetails()`
|
|
149
|
+
|
|
150
|
+
Get a formatted string with certificate details.
|
|
151
|
+
|
|
152
|
+
**Returns:** `string`
|
|
153
|
+
|
|
154
|
+
**Example:**
|
|
155
|
+
```js
|
|
156
|
+
const details = noskid.getFormattedDetails();
|
|
157
|
+
console.log(details);
|
|
158
|
+
// Output:
|
|
159
|
+
// Certificate Details:
|
|
160
|
+
// - Certificate #: 12345
|
|
161
|
+
// - Username: john_doe
|
|
162
|
+
// - Percentage: 95%
|
|
163
|
+
// - Creation Date: 2024-01-15 14:30:25
|
|
164
|
+
// - Country: United States (US)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Utility Methods
|
|
168
|
+
|
|
169
|
+
#### `reset()`
|
|
170
|
+
|
|
171
|
+
Reset all certificate data and close any open login modals.
|
|
172
|
+
|
|
173
|
+
**Returns:** `void`
|
|
174
|
+
|
|
175
|
+
#### `nskdLbrLog(message, level)`
|
|
176
|
+
|
|
177
|
+
Log messages with different levels (when debug is enabled).
|
|
178
|
+
|
|
179
|
+
**Parameters:**
|
|
180
|
+
- `message` (`string`) - Message to log
|
|
181
|
+
- `level` (`string`) - Log level: `'info'`, `'error'`, `'warning'`, `'success'`
|
|
182
|
+
|
|
183
|
+
**Returns:** `void`
|
|
184
|
+
|
|
185
|
+
## Login with NoSkid
|
|
186
|
+
|
|
187
|
+
The library provides a complete login system with a responsive modal interface.
|
|
188
|
+
|
|
189
|
+
If you want a clean login button, please use this one:
|
|
190
|
+

|
|
191
|
+
|
|
192
|
+
### `showLoginModal()`
|
|
193
|
+
|
|
194
|
+
Display a login modal for certificate-based authentication.
|
|
195
|
+
|
|
196
|
+
**Requirements:**
|
|
197
|
+
- Browser environment only
|
|
198
|
+
- `loginEndpoint` must be configured
|
|
199
|
+
- Valid login API endpoint that accepts POST requests
|
|
200
|
+
|
|
201
|
+
**Returns:** `Promise<LoginResult>`
|
|
202
|
+
|
|
203
|
+
**Example:**
|
|
204
|
+
```js
|
|
205
|
+
const noskid = new NskdLbr({
|
|
206
|
+
loginEndpoint: 'https://your-api.com/login',
|
|
207
|
+
onLoginSuccess: (result, certData) => {
|
|
208
|
+
console.log('Welcome', certData.localUsername);
|
|
209
|
+
// Redirect user, update UI, etc.
|
|
210
|
+
},
|
|
211
|
+
onLoginFail: (error, certData) => {
|
|
212
|
+
console.error('Login failed:', error.message);
|
|
213
|
+
// Show error message, etc.
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Show login modal
|
|
218
|
+
try {
|
|
219
|
+
const loginResult = await noskid.showLoginModal();
|
|
220
|
+
console.log('Login successful:', loginResult);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.log('Login cancelled:', error.message);
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Login API Format
|
|
227
|
+
|
|
228
|
+
Your login endpoint should accept POST requests with this format:
|
|
229
|
+
|
|
230
|
+
**Request:**
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"certificate": {
|
|
234
|
+
"key": "a1b2c3d4e5f6789...",
|
|
235
|
+
"username": "john_doe",
|
|
236
|
+
"certificate_number": "12345",
|
|
237
|
+
"percentage": 95,
|
|
238
|
+
"country": "United States",
|
|
239
|
+
"countryCode": "US",
|
|
240
|
+
"creationDate": "2024-01-15 14:30:25"
|
|
241
|
+
},
|
|
242
|
+
"password": "user_password"
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Response:**
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"success": true,
|
|
250
|
+
"message": "Login successful",
|
|
251
|
+
"data": {
|
|
252
|
+
"token": "jwt_token_here",
|
|
253
|
+
"user": {...}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
91
257
|
|
|
92
|
-
|
|
258
|
+
## Response Objects
|
|
93
259
|
|
|
94
|
-
|
|
95
|
-
| - | - | - |
|
|
96
|
-
| `loadFromFile(file)` | Load and verify a certificate from a PNG file | `Promise<Object>` Verification result |
|
|
97
|
-
| `verifyWithKey(key)` | Verify a certificate using a verification key | `Promise<Object>` Verification result |
|
|
98
|
-
| `getCertificateData()` | Get the current certificate data | `Object|null` Certificate data or null |
|
|
99
|
-
| `isValidCertificate()` | Check if the certificate is valid | `boolean` |
|
|
100
|
-
| `getFormattedDetails()` | Get formatted certificate details | `string` |
|
|
101
|
-
| `reset()` | Reset the certificate data | `void` |
|
|
260
|
+
### VerificationResult
|
|
102
261
|
|
|
103
|
-
|
|
262
|
+
```js
|
|
263
|
+
interface VerificationResult {
|
|
264
|
+
valid: boolean; // Whether certificate is valid
|
|
265
|
+
message: string; // Status message
|
|
266
|
+
data?: CertificateData; // Certificate data (if valid)
|
|
267
|
+
cached?: boolean; // Whether result was cached
|
|
268
|
+
strictCheck?: boolean; // Whether strict checking was used
|
|
269
|
+
}
|
|
270
|
+
```
|
|
104
271
|
|
|
105
|
-
|
|
272
|
+
### CertificateData
|
|
106
273
|
|
|
107
274
|
```js
|
|
108
|
-
|
|
275
|
+
interface CertificateData {
|
|
276
|
+
certificate_number: string; // Certificate number
|
|
277
|
+
username: string; // Username from API
|
|
278
|
+
nickname?: string; // Nickname (if not using legacy API)
|
|
279
|
+
percentage: number; // NoSkid percentage
|
|
280
|
+
country: string; // Country name
|
|
281
|
+
countryCode: string; // ISO country code
|
|
282
|
+
creationDate: string; // Certificate creation date
|
|
283
|
+
key: string; // Verification key
|
|
284
|
+
localUsername?: string; // Username from local certificate
|
|
285
|
+
localCreationDate?: string; // Creation date from local certificate
|
|
286
|
+
}
|
|
109
287
|
```
|
|
110
288
|
|
|
111
|
-
|
|
289
|
+
### LoginResult
|
|
112
290
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
291
|
+
```js
|
|
292
|
+
interface LoginResult {
|
|
293
|
+
success: boolean; // Whether login was successful
|
|
294
|
+
data: CertificateData; // Certificate data
|
|
295
|
+
response: any; // API response from login endpoint
|
|
296
|
+
}
|
|
297
|
+
```
|
|
117
298
|
|
|
118
299
|
## Examples
|
|
119
300
|
|
|
120
|
-
###
|
|
301
|
+
### Basic Certificate Verification
|
|
121
302
|
|
|
122
303
|
```js
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
304
|
+
const noskid = new NskdLbr({ debug: true });
|
|
305
|
+
|
|
306
|
+
// From file
|
|
307
|
+
document.getElementById('file-input').addEventListener('change', async (e) => {
|
|
308
|
+
try {
|
|
309
|
+
const result = await noskid.loadFromFile(e.target.files[0]);
|
|
310
|
+
|
|
311
|
+
if (result.valid) {
|
|
312
|
+
const certData = noskid.getCertificateData();
|
|
313
|
+
console.log(`Certificate #${certData.certificate_number} is valid!`);
|
|
314
|
+
console.log(`User: ${certData.username} (${certData.percentage}%)`);
|
|
315
|
+
} else {
|
|
316
|
+
console.log('Invalid certificate:', result.message);
|
|
317
|
+
}
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error('Verification failed:', error.message);
|
|
127
320
|
}
|
|
128
321
|
});
|
|
322
|
+
|
|
323
|
+
// From verification key
|
|
324
|
+
const key = 'a1b2c3d4e5f6789abcdef...'; // 64-char hex string
|
|
325
|
+
try {
|
|
326
|
+
const result = await noskid.verifyWithKey(key);
|
|
327
|
+
console.log('Verification result:', result);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.error('Error:', error.message);
|
|
330
|
+
}
|
|
129
331
|
```
|
|
130
332
|
|
|
131
|
-
###
|
|
333
|
+
### Complete Login Implementation
|
|
132
334
|
|
|
133
335
|
```js
|
|
134
|
-
const
|
|
135
|
-
|
|
336
|
+
const noskid = new NskdLbr({
|
|
337
|
+
debug: true,
|
|
338
|
+
loginEndpoint: 'https://api.yoursite.com/auth/noskid',
|
|
339
|
+
onLoginSuccess: (result, certData) => {
|
|
340
|
+
// Store authentication token
|
|
341
|
+
localStorage.setItem('auth_token', result.response.token);
|
|
342
|
+
|
|
343
|
+
// Update UI
|
|
344
|
+
document.getElementById('login-btn').style.display = 'none';
|
|
345
|
+
document.getElementById('user-info').textContent =
|
|
346
|
+
`Welcome, ${certData.localUsername}!`;
|
|
347
|
+
|
|
348
|
+
// Redirect or update application state
|
|
349
|
+
window.location.href = '/dashboard';
|
|
350
|
+
},
|
|
351
|
+
onLoginFail: (error, certData) => {
|
|
352
|
+
// Show error message
|
|
353
|
+
alert(`Login failed: ${error.message}`);
|
|
354
|
+
|
|
355
|
+
// Log for debugging
|
|
356
|
+
console.error('Login error:', error);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Add login button event
|
|
361
|
+
document.getElementById('noskid-login-btn').addEventListener('click', async () => {
|
|
362
|
+
try {
|
|
363
|
+
await noskid.showLoginModal();
|
|
364
|
+
} catch (error) {
|
|
365
|
+
if (error.message !== 'Login cancelled') {
|
|
366
|
+
console.error('Login error:', error);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
136
369
|
});
|
|
137
370
|
```
|
|
138
371
|
|
|
139
|
-
|
|
372
|
+
### Custom Configuration
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
const noskid = new NskdLbr({
|
|
376
|
+
apiUrl: 'https://custom-api.example.com/verify',
|
|
377
|
+
timeout: 15000,
|
|
378
|
+
strictCheck: false,
|
|
379
|
+
useLegacyAPI: true,
|
|
380
|
+
onLog: (message, level) => {
|
|
381
|
+
// Send logs to analytics service
|
|
382
|
+
analytics.track('noskid_log', { message, level });
|
|
383
|
+
|
|
384
|
+
// Custom console formatting
|
|
385
|
+
const timestamp = new Date().toISOString();
|
|
386
|
+
console.log(`[${timestamp}] [${level.toUpperCase()}] ${message}`);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
```
|
|
140
390
|
|
|
141
|
-
|
|
391
|
+
### Handling Different Error Cases
|
|
142
392
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
393
|
+
```js
|
|
394
|
+
try {
|
|
395
|
+
const result = await noskid.loadFromFile(file);
|
|
396
|
+
|
|
397
|
+
if (result.valid) {
|
|
398
|
+
console.log('✅ Certificate is valid');
|
|
399
|
+
} else {
|
|
400
|
+
// Handle different failure reasons
|
|
401
|
+
if (result.strictCheck && result.message.includes('mismatch')) {
|
|
402
|
+
console.log('⚠️ Certificate data mismatch - try disabling strict check');
|
|
403
|
+
} else {
|
|
404
|
+
console.log('❌ Certificate verification failed:', result.message);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
} catch (error) {
|
|
408
|
+
// Handle different error types
|
|
409
|
+
if (error.message.includes('timeout')) {
|
|
410
|
+
console.log('🕐 Request timed out - server may be slow');
|
|
411
|
+
} else if (error.message.includes('PNG')) {
|
|
412
|
+
console.log('📄 Invalid file format - please upload a PNG certificate');
|
|
413
|
+
} else if (error.message.includes('verification key')) {
|
|
414
|
+
console.log('🔑 Invalid verification key format');
|
|
415
|
+
} else {
|
|
416
|
+
console.log('💥 Unexpected error:', error.message);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
147
420
|
|
|
148
421
|
## Error Handling
|
|
149
422
|
|
|
150
|
-
The library
|
|
423
|
+
The library provides detailed error messages for different failure scenarios:
|
|
151
424
|
|
|
152
|
-
|
|
425
|
+
### Common Errors
|
|
426
|
+
|
|
427
|
+
| Error Type | Cause | Solution |
|
|
428
|
+
|------------|-------|----------|
|
|
429
|
+
| `"No file provided"` | File input is empty | Check file selection |
|
|
430
|
+
| `"File must be a PNG image"` | Wrong file format | Upload a PNG certificate |
|
|
431
|
+
| `"No valid verification key found"` | Certificate missing key | Check certificate validity |
|
|
432
|
+
| `"Request timeout"` | Network/server issues | Check connection, increase timeout |
|
|
433
|
+
| `"Data mismatch"` | Local vs API data differs | Disable `strictCheck` or verify certificate |
|
|
434
|
+
| `"Login endpoint is not configured"` | Missing login endpoint | Set `loginEndpoint` option |
|
|
435
|
+
| `"Login modal is only available in browser"` | Node.js environment | Use in browser only |
|
|
436
|
+
|
|
437
|
+
### Best Practices
|
|
438
|
+
|
|
439
|
+
```js
|
|
440
|
+
// Always wrap in try-catch
|
|
153
441
|
try {
|
|
154
|
-
const result = await
|
|
155
|
-
// Handle
|
|
442
|
+
const result = await noskid.loadFromFile(file);
|
|
443
|
+
// Handle result
|
|
156
444
|
} catch (error) {
|
|
157
|
-
|
|
445
|
+
// Handle error appropriately
|
|
446
|
+
console.error('Certificate verification failed:', error.message);
|
|
158
447
|
}
|
|
448
|
+
|
|
449
|
+
// Check if certificate is loaded before accessing data
|
|
450
|
+
if (noskid.isValidCertificate()) {
|
|
451
|
+
const data = noskid.getCertificateData();
|
|
452
|
+
// Use certificate data
|
|
453
|
+
} else {
|
|
454
|
+
console.log('No valid certificate loaded');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Reset state when needed
|
|
458
|
+
noskid.reset(); // Clears all data and closes modals
|
|
159
459
|
```
|
|
160
460
|
|
|
461
|
+
## Browser Support
|
|
462
|
+
|
|
463
|
+
- **Modern Browsers**: Chrome 60+, Firefox 55+, Safari 12+, Edge 79+
|
|
464
|
+
- **Features Used**: Fetch API, Promises, File API, TextDecoder
|
|
465
|
+
- **Polyfills**: May require polyfills for older browsers
|
|
466
|
+
|
|
467
|
+
### Required Browser APIs
|
|
468
|
+
|
|
469
|
+
- `fetch()` - for API requests
|
|
470
|
+
- `FileReader` - for reading certificate files
|
|
471
|
+
- `TextDecoder` - for PNG text extraction
|
|
472
|
+
- `AbortController` - for request timeouts
|
|
473
|
+
|
|
161
474
|
## Contributing
|
|
162
475
|
|
|
163
|
-
Contributions are welcome! Please
|
|
476
|
+
Contributions are welcome! Please follow these guidelines:
|
|
477
|
+
|
|
478
|
+
1. Fork the repository
|
|
479
|
+
2. Create a feature branch
|
|
480
|
+
3. Add tests for new functionality
|
|
481
|
+
4. Ensure all tests pass
|
|
482
|
+
5. Submit a pull request
|
|
164
483
|
|
|
165
484
|
## License
|
|
166
485
|
|
|
167
|
-
This library is licensed under the NSDv1.0 License. See the LICENSE file for
|
|
486
|
+
This library is licensed under the NSDv1.0 License. See the [LICENSE](LICENSE) file for details.
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
**Need Help?**
|
|
491
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/douxxtech/noskid.today/issues)
|
|
492
|
+
|
|
493
|
+
<a align="center" href="https://github.com/douxxtech" target="_blank">
|
|
494
|
+
<img src="https://madeby.douxx.tech"></img>
|
|
495
|
+
</a>
|
package/package.json
CHANGED
package/src/login.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 60"><defs><linearGradient id="buttonGradient" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" style="stop-color:#fcfaf5;stop-opacity:1"/><stop offset="100%" style="stop-color:#f0ede0;stop-opacity:1"/></linearGradient><pattern id="texturePattern" width="4" height="4" patternUnits="userSpaceOnUse"><rect width="4" height="4" fill="#f9f7f0"/><circle cx="2" cy="2" r="0.3" fill="#e8e5d8" opacity="0.3"/></pattern></defs><rect x="5" y="5" width="310" height="50" rx="8" ry="8" fill="url(#buttonGradient)" stroke="#8b4513" stroke-width="2"/><rect x="5" y="5" width="310" height="50" rx="8" ry="8" fill="url(#texturePattern)" opacity="0.4"/><rect x="8" y="8" width="304" height="44" rx="6" ry="6" fill="none" stroke="#8b4513" stroke-width="1" opacity="0.6"/><circle cx="25" cy="30" r="3" fill="#8b4513" opacity="0.7"/><circle cx="295" cy="30" r="3" fill="#8b4513" opacity="0.7"/><line x1="35" y1="30" x2="45" y2="30" stroke="#8b4513" stroke-width="1.5" opacity="0.5"/><line x1="275" y1="30" x2="285" y2="30" stroke="#8b4513" stroke-width="1.5" opacity="0.5"/><text x="160" y="35" fill="#8b4513" font-size="16" font-family="'Times New Roman', serif" font-weight="bold" text-anchor="middle">Login with NoSkid</text></svg>
|