nskd-lbr 1.0.2 → 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 -78
- package/package.json +1 -1
- package/src/login.svg +1 -0
- package/src/nskd-lbr.js +775 -9
- 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,136 +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
|
-
|
|
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
|
+
```
|
|
90
257
|
|
|
91
|
-
|
|
258
|
+
## Response Objects
|
|
92
259
|
|
|
93
|
-
|
|
94
|
-
| - | - | - |
|
|
95
|
-
| `loadFromFile(file)` | Load and verify a certificate from a PNG file | `Promise<Object>` Verification result |
|
|
96
|
-
| `verifyWithKey(key)` | Verify a certificate using a verification key | `Promise<Object>` Verification result |
|
|
97
|
-
| `getCertificateData()` | Get the current certificate data | `Object|null` Certificate data or null |
|
|
98
|
-
| `isValidCertificate()` | Check if the certificate is valid | `boolean` |
|
|
99
|
-
| `getFormattedDetails()` | Get formatted certificate details | `string` |
|
|
100
|
-
| `reset()` | Reset the certificate data | `void` |
|
|
260
|
+
### VerificationResult
|
|
101
261
|
|
|
102
|
-
|
|
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
|
+
```
|
|
103
271
|
|
|
104
|
-
|
|
272
|
+
### CertificateData
|
|
105
273
|
|
|
106
274
|
```js
|
|
107
|
-
|
|
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
|
+
}
|
|
108
287
|
```
|
|
109
288
|
|
|
110
|
-
|
|
289
|
+
### LoginResult
|
|
111
290
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
+
```
|
|
116
298
|
|
|
117
299
|
## Examples
|
|
118
300
|
|
|
119
|
-
###
|
|
301
|
+
### Basic Certificate Verification
|
|
120
302
|
|
|
121
303
|
```js
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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);
|
|
126
320
|
}
|
|
127
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
|
+
}
|
|
128
331
|
```
|
|
129
332
|
|
|
130
|
-
###
|
|
333
|
+
### Complete Login Implementation
|
|
131
334
|
|
|
132
335
|
```js
|
|
133
|
-
const
|
|
134
|
-
|
|
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
|
+
}
|
|
135
369
|
});
|
|
136
370
|
```
|
|
137
371
|
|
|
138
|
-
|
|
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
|
+
```
|
|
139
390
|
|
|
140
|
-
|
|
391
|
+
### Handling Different Error Cases
|
|
141
392
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
+
```
|
|
146
420
|
|
|
147
421
|
## Error Handling
|
|
148
422
|
|
|
149
|
-
The library
|
|
423
|
+
The library provides detailed error messages for different failure scenarios:
|
|
150
424
|
|
|
151
|
-
|
|
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
|
|
152
441
|
try {
|
|
153
|
-
const result = await
|
|
154
|
-
// Handle
|
|
442
|
+
const result = await noskid.loadFromFile(file);
|
|
443
|
+
// Handle result
|
|
155
444
|
} catch (error) {
|
|
156
|
-
|
|
445
|
+
// Handle error appropriately
|
|
446
|
+
console.error('Certificate verification failed:', error.message);
|
|
157
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
|
|
158
459
|
```
|
|
159
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
|
+
|
|
160
474
|
## Contributing
|
|
161
475
|
|
|
162
|
-
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
|
|
163
483
|
|
|
164
484
|
## License
|
|
165
485
|
|
|
166
|
-
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>
|