mirror of
https://github.com/dergigi/boris.git
synced 2025-12-18 23:24:22 +01:00
feat: initialize markr nostr bookmark client
- Add project structure with TypeScript, React, and Vite - Implement nostr authentication using browser extension (NIP-07) - Add NIP-51 compliant bookmark fetching and display - Create minimal UI with login and bookmark components - Integrate applesauce-core and applesauce-react libraries - Add responsive styling with dark/light mode support - Include comprehensive README with setup instructions This is a minimal MVP for a nostr bookmark client that allows users to view their bookmarks according to NIP-51 specification.
This commit is contained in:
360
node_modules/@noble/curves/utils.js
generated
vendored
Normal file
360
node_modules/@noble/curves/utils.js
generated
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.notImplemented = exports.bitMask = exports.utf8ToBytes = exports.randomBytes = exports.isBytes = exports.hexToBytes = exports.concatBytes = exports.bytesToUtf8 = exports.bytesToHex = exports.anumber = exports.abytes = void 0;
|
||||
exports.abool = abool;
|
||||
exports._abool2 = _abool2;
|
||||
exports._abytes2 = _abytes2;
|
||||
exports.numberToHexUnpadded = numberToHexUnpadded;
|
||||
exports.hexToNumber = hexToNumber;
|
||||
exports.bytesToNumberBE = bytesToNumberBE;
|
||||
exports.bytesToNumberLE = bytesToNumberLE;
|
||||
exports.numberToBytesBE = numberToBytesBE;
|
||||
exports.numberToBytesLE = numberToBytesLE;
|
||||
exports.numberToVarBytesBE = numberToVarBytesBE;
|
||||
exports.ensureBytes = ensureBytes;
|
||||
exports.equalBytes = equalBytes;
|
||||
exports.copyBytes = copyBytes;
|
||||
exports.asciiToBytes = asciiToBytes;
|
||||
exports.inRange = inRange;
|
||||
exports.aInRange = aInRange;
|
||||
exports.bitLen = bitLen;
|
||||
exports.bitGet = bitGet;
|
||||
exports.bitSet = bitSet;
|
||||
exports.createHmacDrbg = createHmacDrbg;
|
||||
exports.validateObject = validateObject;
|
||||
exports.isHash = isHash;
|
||||
exports._validateObject = _validateObject;
|
||||
exports.memoized = memoized;
|
||||
/**
|
||||
* Hex, bytes and number utilities.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
const utils_js_1 = require("@noble/hashes/utils.js");
|
||||
var utils_js_2 = require("@noble/hashes/utils.js");
|
||||
Object.defineProperty(exports, "abytes", { enumerable: true, get: function () { return utils_js_2.abytes; } });
|
||||
Object.defineProperty(exports, "anumber", { enumerable: true, get: function () { return utils_js_2.anumber; } });
|
||||
Object.defineProperty(exports, "bytesToHex", { enumerable: true, get: function () { return utils_js_2.bytesToHex; } });
|
||||
Object.defineProperty(exports, "bytesToUtf8", { enumerable: true, get: function () { return utils_js_2.bytesToUtf8; } });
|
||||
Object.defineProperty(exports, "concatBytes", { enumerable: true, get: function () { return utils_js_2.concatBytes; } });
|
||||
Object.defineProperty(exports, "hexToBytes", { enumerable: true, get: function () { return utils_js_2.hexToBytes; } });
|
||||
Object.defineProperty(exports, "isBytes", { enumerable: true, get: function () { return utils_js_2.isBytes; } });
|
||||
Object.defineProperty(exports, "randomBytes", { enumerable: true, get: function () { return utils_js_2.randomBytes; } });
|
||||
Object.defineProperty(exports, "utf8ToBytes", { enumerable: true, get: function () { return utils_js_2.utf8ToBytes; } });
|
||||
const _0n = /* @__PURE__ */ BigInt(0);
|
||||
const _1n = /* @__PURE__ */ BigInt(1);
|
||||
function abool(title, value) {
|
||||
if (typeof value !== 'boolean')
|
||||
throw new Error(title + ' boolean expected, got ' + value);
|
||||
}
|
||||
// tmp name until v2
|
||||
function _abool2(value, title = '') {
|
||||
if (typeof value !== 'boolean') {
|
||||
const prefix = title && `"${title}"`;
|
||||
throw new Error(prefix + 'expected boolean, got type=' + typeof value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
// tmp name until v2
|
||||
/** Asserts something is Uint8Array. */
|
||||
function _abytes2(value, length, title = '') {
|
||||
const bytes = (0, utils_js_1.isBytes)(value);
|
||||
const len = value?.length;
|
||||
const needsLen = length !== undefined;
|
||||
if (!bytes || (needsLen && len !== length)) {
|
||||
const prefix = title && `"${title}" `;
|
||||
const ofLen = needsLen ? ` of length ${length}` : '';
|
||||
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
||||
throw new Error(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
// Used in weierstrass, der
|
||||
function numberToHexUnpadded(num) {
|
||||
const hex = num.toString(16);
|
||||
return hex.length & 1 ? '0' + hex : hex;
|
||||
}
|
||||
function hexToNumber(hex) {
|
||||
if (typeof hex !== 'string')
|
||||
throw new Error('hex string expected, got ' + typeof hex);
|
||||
return hex === '' ? _0n : BigInt('0x' + hex); // Big Endian
|
||||
}
|
||||
// BE: Big Endian, LE: Little Endian
|
||||
function bytesToNumberBE(bytes) {
|
||||
return hexToNumber((0, utils_js_1.bytesToHex)(bytes));
|
||||
}
|
||||
function bytesToNumberLE(bytes) {
|
||||
(0, utils_js_1.abytes)(bytes);
|
||||
return hexToNumber((0, utils_js_1.bytesToHex)(Uint8Array.from(bytes).reverse()));
|
||||
}
|
||||
function numberToBytesBE(n, len) {
|
||||
return (0, utils_js_1.hexToBytes)(n.toString(16).padStart(len * 2, '0'));
|
||||
}
|
||||
function numberToBytesLE(n, len) {
|
||||
return numberToBytesBE(n, len).reverse();
|
||||
}
|
||||
// Unpadded, rarely used
|
||||
function numberToVarBytesBE(n) {
|
||||
return (0, utils_js_1.hexToBytes)(numberToHexUnpadded(n));
|
||||
}
|
||||
/**
|
||||
* Takes hex string or Uint8Array, converts to Uint8Array.
|
||||
* Validates output length.
|
||||
* Will throw error for other types.
|
||||
* @param title descriptive title for an error e.g. 'secret key'
|
||||
* @param hex hex string or Uint8Array
|
||||
* @param expectedLength optional, will compare to result array's length
|
||||
* @returns
|
||||
*/
|
||||
function ensureBytes(title, hex, expectedLength) {
|
||||
let res;
|
||||
if (typeof hex === 'string') {
|
||||
try {
|
||||
res = (0, utils_js_1.hexToBytes)(hex);
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(title + ' must be hex string or Uint8Array, cause: ' + e);
|
||||
}
|
||||
}
|
||||
else if ((0, utils_js_1.isBytes)(hex)) {
|
||||
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
||||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||||
res = Uint8Array.from(hex);
|
||||
}
|
||||
else {
|
||||
throw new Error(title + ' must be hex string or Uint8Array');
|
||||
}
|
||||
const len = res.length;
|
||||
if (typeof expectedLength === 'number' && len !== expectedLength)
|
||||
throw new Error(title + ' of length ' + expectedLength + ' expected, got ' + len);
|
||||
return res;
|
||||
}
|
||||
// Compares 2 u8a-s in kinda constant time
|
||||
function equalBytes(a, b) {
|
||||
if (a.length !== b.length)
|
||||
return false;
|
||||
let diff = 0;
|
||||
for (let i = 0; i < a.length; i++)
|
||||
diff |= a[i] ^ b[i];
|
||||
return diff === 0;
|
||||
}
|
||||
/**
|
||||
* Copies Uint8Array. We can't use u8a.slice(), because u8a can be Buffer,
|
||||
* and Buffer#slice creates mutable copy. Never use Buffers!
|
||||
*/
|
||||
function copyBytes(bytes) {
|
||||
return Uint8Array.from(bytes);
|
||||
}
|
||||
/**
|
||||
* Decodes 7-bit ASCII string to Uint8Array, throws on non-ascii symbols
|
||||
* Should be safe to use for things expected to be ASCII.
|
||||
* Returns exact same result as utf8ToBytes for ASCII or throws.
|
||||
*/
|
||||
function asciiToBytes(ascii) {
|
||||
return Uint8Array.from(ascii, (c, i) => {
|
||||
const charCode = c.charCodeAt(0);
|
||||
if (c.length !== 1 || charCode > 127) {
|
||||
throw new Error(`string contains non-ASCII character "${ascii[i]}" with code ${charCode} at position ${i}`);
|
||||
}
|
||||
return charCode;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
||||
*/
|
||||
// export const utf8ToBytes: typeof utf8ToBytes_ = utf8ToBytes_;
|
||||
/**
|
||||
* Converts bytes to string using UTF8 encoding.
|
||||
* @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'
|
||||
*/
|
||||
// export const bytesToUtf8: typeof bytesToUtf8_ = bytesToUtf8_;
|
||||
// Is positive bigint
|
||||
const isPosBig = (n) => typeof n === 'bigint' && _0n <= n;
|
||||
function inRange(n, min, max) {
|
||||
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
|
||||
}
|
||||
/**
|
||||
* Asserts min <= n < max. NOTE: It's < max and not <= max.
|
||||
* @example
|
||||
* aInRange('x', x, 1n, 256n); // would assume x is in (1n..255n)
|
||||
*/
|
||||
function aInRange(title, n, min, max) {
|
||||
// Why min <= n < max and not a (min < n < max) OR b (min <= n <= max)?
|
||||
// consider P=256n, min=0n, max=P
|
||||
// - a for min=0 would require -1: `inRange('x', x, -1n, P)`
|
||||
// - b would commonly require subtraction: `inRange('x', x, 0n, P - 1n)`
|
||||
// - our way is the cleanest: `inRange('x', x, 0n, P)
|
||||
if (!inRange(n, min, max))
|
||||
throw new Error('expected valid ' + title + ': ' + min + ' <= n < ' + max + ', got ' + n);
|
||||
}
|
||||
// Bit operations
|
||||
/**
|
||||
* Calculates amount of bits in a bigint.
|
||||
* Same as `n.toString(2).length`
|
||||
* TODO: merge with nLength in modular
|
||||
*/
|
||||
function bitLen(n) {
|
||||
let len;
|
||||
for (len = 0; n > _0n; n >>= _1n, len += 1)
|
||||
;
|
||||
return len;
|
||||
}
|
||||
/**
|
||||
* Gets single bit at position.
|
||||
* NOTE: first bit position is 0 (same as arrays)
|
||||
* Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
|
||||
*/
|
||||
function bitGet(n, pos) {
|
||||
return (n >> BigInt(pos)) & _1n;
|
||||
}
|
||||
/**
|
||||
* Sets single bit at position.
|
||||
*/
|
||||
function bitSet(n, pos, value) {
|
||||
return n | ((value ? _1n : _0n) << BigInt(pos));
|
||||
}
|
||||
/**
|
||||
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
|
||||
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
|
||||
*/
|
||||
const bitMask = (n) => (_1n << BigInt(n)) - _1n;
|
||||
exports.bitMask = bitMask;
|
||||
/**
|
||||
* Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
|
||||
* @returns function that will call DRBG until 2nd arg returns something meaningful
|
||||
* @example
|
||||
* const drbg = createHmacDRBG<Key>(32, 32, hmac);
|
||||
* drbg(seed, bytesToKey); // bytesToKey must return Key or undefined
|
||||
*/
|
||||
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
||||
if (typeof hashLen !== 'number' || hashLen < 2)
|
||||
throw new Error('hashLen must be a number');
|
||||
if (typeof qByteLen !== 'number' || qByteLen < 2)
|
||||
throw new Error('qByteLen must be a number');
|
||||
if (typeof hmacFn !== 'function')
|
||||
throw new Error('hmacFn must be a function');
|
||||
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
|
||||
const u8n = (len) => new Uint8Array(len); // creates Uint8Array
|
||||
const u8of = (byte) => Uint8Array.of(byte); // another shortcut
|
||||
let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
|
||||
let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
|
||||
let i = 0; // Iterations counter, will throw when over 1000
|
||||
const reset = () => {
|
||||
v.fill(1);
|
||||
k.fill(0);
|
||||
i = 0;
|
||||
};
|
||||
const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
|
||||
const reseed = (seed = u8n(0)) => {
|
||||
// HMAC-DRBG reseed() function. Steps D-G
|
||||
k = h(u8of(0x00), seed); // k = hmac(k || v || 0x00 || seed)
|
||||
v = h(); // v = hmac(k || v)
|
||||
if (seed.length === 0)
|
||||
return;
|
||||
k = h(u8of(0x01), seed); // k = hmac(k || v || 0x01 || seed)
|
||||
v = h(); // v = hmac(k || v)
|
||||
};
|
||||
const gen = () => {
|
||||
// HMAC-DRBG generate() function
|
||||
if (i++ >= 1000)
|
||||
throw new Error('drbg: tried 1000 values');
|
||||
let len = 0;
|
||||
const out = [];
|
||||
while (len < qByteLen) {
|
||||
v = h();
|
||||
const sl = v.slice();
|
||||
out.push(sl);
|
||||
len += v.length;
|
||||
}
|
||||
return (0, utils_js_1.concatBytes)(...out);
|
||||
};
|
||||
const genUntil = (seed, pred) => {
|
||||
reset();
|
||||
reseed(seed); // Steps D-G
|
||||
let res = undefined; // Step H: grind until k is in [1..n-1]
|
||||
while (!(res = pred(gen())))
|
||||
reseed();
|
||||
reset();
|
||||
return res;
|
||||
};
|
||||
return genUntil;
|
||||
}
|
||||
// Validating curves and fields
|
||||
const validatorFns = {
|
||||
bigint: (val) => typeof val === 'bigint',
|
||||
function: (val) => typeof val === 'function',
|
||||
boolean: (val) => typeof val === 'boolean',
|
||||
string: (val) => typeof val === 'string',
|
||||
stringOrUint8Array: (val) => typeof val === 'string' || (0, utils_js_1.isBytes)(val),
|
||||
isSafeInteger: (val) => Number.isSafeInteger(val),
|
||||
array: (val) => Array.isArray(val),
|
||||
field: (val, object) => object.Fp.isValid(val),
|
||||
hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
||||
};
|
||||
// type Record<K extends string | number | symbol, T> = { [P in K]: T; }
|
||||
function validateObject(object, validators, optValidators = {}) {
|
||||
const checkField = (fieldName, type, isOptional) => {
|
||||
const checkVal = validatorFns[type];
|
||||
if (typeof checkVal !== 'function')
|
||||
throw new Error('invalid validator function');
|
||||
const val = object[fieldName];
|
||||
if (isOptional && val === undefined)
|
||||
return;
|
||||
if (!checkVal(val, object)) {
|
||||
throw new Error('param ' + String(fieldName) + ' is invalid. Expected ' + type + ', got ' + val);
|
||||
}
|
||||
};
|
||||
for (const [fieldName, type] of Object.entries(validators))
|
||||
checkField(fieldName, type, false);
|
||||
for (const [fieldName, type] of Object.entries(optValidators))
|
||||
checkField(fieldName, type, true);
|
||||
return object;
|
||||
}
|
||||
// validate type tests
|
||||
// const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };
|
||||
// const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!
|
||||
// // Should fail type-check
|
||||
// const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });
|
||||
// const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });
|
||||
// const z3 = validateObject(o, { test: 'boolean', z: 'bug' });
|
||||
// const z4 = validateObject(o, { a: 'boolean', z: 'bug' });
|
||||
function isHash(val) {
|
||||
return typeof val === 'function' && Number.isSafeInteger(val.outputLen);
|
||||
}
|
||||
function _validateObject(object, fields, optFields = {}) {
|
||||
if (!object || typeof object !== 'object')
|
||||
throw new Error('expected valid options object');
|
||||
function checkField(fieldName, expectedType, isOpt) {
|
||||
const val = object[fieldName];
|
||||
if (isOpt && val === undefined)
|
||||
return;
|
||||
const current = typeof val;
|
||||
if (current !== expectedType || val === null)
|
||||
throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`);
|
||||
}
|
||||
Object.entries(fields).forEach(([k, v]) => checkField(k, v, false));
|
||||
Object.entries(optFields).forEach(([k, v]) => checkField(k, v, true));
|
||||
}
|
||||
/**
|
||||
* throws not implemented error
|
||||
*/
|
||||
const notImplemented = () => {
|
||||
throw new Error('not implemented');
|
||||
};
|
||||
exports.notImplemented = notImplemented;
|
||||
/**
|
||||
* Memoizes (caches) computation result.
|
||||
* Uses WeakMap: the value is going auto-cleaned by GC after last reference is removed.
|
||||
*/
|
||||
function memoized(fn) {
|
||||
const map = new WeakMap();
|
||||
return (arg, ...args) => {
|
||||
const val = map.get(arg);
|
||||
if (val !== undefined)
|
||||
return val;
|
||||
const computed = fn(arg, ...args);
|
||||
map.set(arg, computed);
|
||||
return computed;
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=utils.js.map
|
||||
Reference in New Issue
Block a user