inslash 1.1.1 → 1.2.1
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 +36 -0
- package/index.js +116 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,8 +35,44 @@ const verifyResult = await verify("myPassword", result.passport, secret);
|
|
|
35
35
|
console.log(verifyResult.valid); // true or false
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## API Mode (Hosted Hashing)
|
|
39
|
+
|
|
40
|
+
`inslash` can connect to a hosted API for password hashing, with automatic fallback to local crypto if the API is unavailable.
|
|
41
|
+
|
|
42
|
+
### Setup
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
const inslash = require('inslash');
|
|
46
|
+
|
|
47
|
+
// Configure once with your API key
|
|
48
|
+
inslash.configure({
|
|
49
|
+
apiKey: 'inslash_your_api_key_here',
|
|
50
|
+
apiUrl: 'https://api.inslash.com' // or http://localhost:3001 for testing
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Now hash() and verify() automatically use the API
|
|
54
|
+
const result = await inslash.hash('myPassword');
|
|
55
|
+
const verified = await inslash.verify('myPassword', result.passport);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### How It Works
|
|
59
|
+
|
|
60
|
+
1. **API First**: When configured, `hash()` and `verify()` call your hosted API
|
|
61
|
+
2. **Silent Fallback**: If the API is down or slow, falls back to local crypto automatically
|
|
62
|
+
3. **Zero Config Local**: If not configured, uses local crypto only (no secret needed from you)
|
|
63
|
+
|
|
64
|
+
### Get an API Key
|
|
65
|
+
|
|
66
|
+
Visit [https://inslash.com](https://inslash.com) to create a project and get your API key.
|
|
67
|
+
|
|
38
68
|
## API
|
|
39
69
|
|
|
70
|
+
### `configure(options)`
|
|
71
|
+
- `options.apiKey` (string): Your Inslash API key.
|
|
72
|
+
- `options.apiUrl` (string): API endpoint URL.
|
|
73
|
+
- **Returns:** Current configuration object.
|
|
74
|
+
- **Note:** Call this once before using `hash()` or `verify()` to enable API mode.
|
|
75
|
+
|
|
40
76
|
### `async hash(value, secret, options?)`
|
|
41
77
|
- `value` (string): The value to hash.
|
|
42
78
|
- `secret` (string): Secret key for HMAC.
|
package/index.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
const crypto = require("crypto");
|
|
2
|
+
const https = require("https");
|
|
3
|
+
const http = require("http");
|
|
4
|
+
|
|
5
|
+
// Module-level configuration for API mode
|
|
6
|
+
let CONFIG = {
|
|
7
|
+
apiKey: null,
|
|
8
|
+
apiUrl: null,
|
|
9
|
+
strictMode: false // If true, throw error instead of falling back to local
|
|
10
|
+
};
|
|
2
11
|
|
|
3
12
|
const DEFAULTS = {
|
|
4
13
|
saltLength: 16,
|
|
@@ -108,11 +117,90 @@ const decodePassport = (passport) => {
|
|
|
108
117
|
}
|
|
109
118
|
};
|
|
110
119
|
|
|
111
|
-
//
|
|
120
|
+
// Helper: Call API endpoint
|
|
121
|
+
const callAPI = (endpoint, body) => {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const url = new URL(endpoint, CONFIG.apiUrl);
|
|
124
|
+
const client = url.protocol === 'https:' ? https : http;
|
|
125
|
+
|
|
126
|
+
const postData = JSON.stringify(body);
|
|
127
|
+
const options = {
|
|
128
|
+
hostname: url.hostname,
|
|
129
|
+
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
130
|
+
path: url.pathname,
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: {
|
|
133
|
+
'Content-Type': 'application/json',
|
|
134
|
+
'x-api-key': CONFIG.apiKey,
|
|
135
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
136
|
+
},
|
|
137
|
+
timeout: 10000
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const req = client.request(options, (res) => {
|
|
141
|
+
let data = '';
|
|
142
|
+
res.on('data', chunk => data += chunk);
|
|
143
|
+
res.on('end', () => {
|
|
144
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
145
|
+
try {
|
|
146
|
+
resolve(JSON.parse(data));
|
|
147
|
+
} catch (e) {
|
|
148
|
+
reject(new Error('Invalid JSON response'));
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
reject(new Error(`API error: ${res.statusCode}`));
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
req.on('error', reject);
|
|
157
|
+
req.on('timeout', () => {
|
|
158
|
+
req.destroy();
|
|
159
|
+
reject(new Error('API request timeout'));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
req.write(postData);
|
|
163
|
+
req.end();
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Configure API mode
|
|
168
|
+
const configure = (options = {}) => {
|
|
169
|
+
const { apiKey, apiUrl, strictMode } = options;
|
|
170
|
+
|
|
171
|
+
if (apiKey) CONFIG.apiKey = apiKey;
|
|
172
|
+
if (apiUrl) CONFIG.apiUrl = apiUrl;
|
|
173
|
+
if (typeof strictMode !== 'undefined') CONFIG.strictMode = strictMode;
|
|
174
|
+
|
|
175
|
+
return CONFIG;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Enhanced: Hash function with more options and API support
|
|
112
179
|
const hash = async (value, secret, opts = {}) => {
|
|
113
|
-
if (!secret) throw new Error("Secret key is required");
|
|
114
180
|
if (typeof value !== "string" || !value) throw new Error("Value to hash must be a non-empty string");
|
|
115
181
|
|
|
182
|
+
// API Mode: Try API first if configured
|
|
183
|
+
if (CONFIG.apiKey && CONFIG.apiUrl) {
|
|
184
|
+
try {
|
|
185
|
+
const apiResult = await callAPI('/api/hash', {
|
|
186
|
+
value,
|
|
187
|
+
secret,
|
|
188
|
+
options: opts
|
|
189
|
+
});
|
|
190
|
+
return apiResult;
|
|
191
|
+
} catch (error) {
|
|
192
|
+
// In strict mode, throw the error instead of falling back
|
|
193
|
+
if (CONFIG.strictMode) {
|
|
194
|
+
throw new Error(`API hash failed: ${error.message}`);
|
|
195
|
+
}
|
|
196
|
+
// Silent fallback to local crypto
|
|
197
|
+
console.warn('API hash failed, falling back to local:', error.message);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Local Mode: Original crypto implementation
|
|
202
|
+
if (!secret) throw new Error("Secret key is required");
|
|
203
|
+
|
|
116
204
|
// Validate algorithm
|
|
117
205
|
if (opts.algorithm && !SUPPORTED_ALGORITHMS.includes(opts.algorithm)) {
|
|
118
206
|
throw new Error(`Unsupported algorithm: ${opts.algorithm}. Supported: ${SUPPORTED_ALGORITHMS.join(", ")}`);
|
|
@@ -155,8 +243,29 @@ const hash = async (value, secret, opts = {}) => {
|
|
|
155
243
|
};
|
|
156
244
|
};
|
|
157
245
|
|
|
158
|
-
// Enhanced: Verify with more detailed response
|
|
246
|
+
// Enhanced: Verify with more detailed response and API support
|
|
159
247
|
const verify = async (value, passport, secret, opts = {}) => {
|
|
248
|
+
// API Mode: Try API first if configured
|
|
249
|
+
if (CONFIG.apiKey && CONFIG.apiUrl) {
|
|
250
|
+
try {
|
|
251
|
+
const apiResult = await callAPI('/api/verify', {
|
|
252
|
+
value,
|
|
253
|
+
passport,
|
|
254
|
+
secret,
|
|
255
|
+
options: opts
|
|
256
|
+
});
|
|
257
|
+
return apiResult;
|
|
258
|
+
} catch (error) {
|
|
259
|
+
// In strict mode, throw the error instead of falling back
|
|
260
|
+
if (CONFIG.strictMode) {
|
|
261
|
+
throw new Error(`API verify failed: ${error.message}`);
|
|
262
|
+
}
|
|
263
|
+
// Silent fallback to local crypto
|
|
264
|
+
console.warn('API verify failed, falling back to local:', error.message);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Local Mode: Original crypto implementation
|
|
160
269
|
const meta = decodePassport(passport);
|
|
161
270
|
const options = {
|
|
162
271
|
algorithm: meta.algorithm,
|
|
@@ -372,6 +481,9 @@ module.exports = {
|
|
|
372
481
|
encodePassport,
|
|
373
482
|
decodePassport,
|
|
374
483
|
|
|
484
|
+
// API configuration
|
|
485
|
+
configure,
|
|
486
|
+
|
|
375
487
|
// New enhanced functions
|
|
376
488
|
batchVerify,
|
|
377
489
|
inspectPassport,
|
|
@@ -385,5 +497,5 @@ module.exports = {
|
|
|
385
497
|
SUPPORTED_ENCODINGS,
|
|
386
498
|
|
|
387
499
|
// Version info
|
|
388
|
-
VERSION: "1.
|
|
500
|
+
VERSION: "1.2.0"
|
|
389
501
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inslash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "A modern, upgradeable, and secure password hashing utility with passport encoding, hash ancestry, and comprehensive security features.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|