@zeroad.network/token 0.9.1 → 0.10.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 CHANGED
@@ -40,7 +40,7 @@ bun add @zeroad.network/token
40
40
 
41
41
  # Examples
42
42
 
43
- Take the example as a reference only. The most basic, and honestly, quite complete use with `express` could look similar to this:
43
+ Take the example as a reference only. The most basic, and honestly, quite complete use with `express` v.5 could look similar to this:
44
44
 
45
45
  ```js
46
46
  import express from "express";
@@ -56,41 +56,44 @@ const app = express();
56
56
  const port = 3000;
57
57
 
58
58
  // Welcome Header Value acquired during Site Registration process at Zero Ad Network platform
59
- const ZERO_AD_PARTNER_HEADER_VALUE = "AZqnKU56eIC7vCD1PPlwhg^1^3";
59
+ const ZERO_AD_NETWORK_WELCOME_HEADER_VALUE = "AZqnKU56eIC7vCD1PPlwhg^1^3";
60
60
 
61
61
  // Initialize your Zero Ad Network module
62
- init({ value: ZERO_AD_PARTNER_HEADER_VALUE });
62
+ init({ value: ZERO_AD_NETWORK_WELCOME_HEADER_VALUE });
63
63
 
64
64
  app
65
- .use((req, res, next) => {
66
- // X-Better-Web-Welcome header injection can could have it's own simple middleware like this:
67
- res.header(getServerHeaderName(), getServerHeaderValue())
68
- })
69
- .use((req, res, next) => {
70
- const result = await processRequest(c.req.header(getClientHeaderName()));
71
-
72
- res.locals.disableAds = result.shouldRemoveAds();
73
- res.locals.removePaywalls = result.shouldEnablePremiumContentAccess();
74
- res.locals.vipExperience = result.shouldEnableVipExperience();
75
-
76
- next();
77
- })
78
- .get('/', (req, res) => {
79
- // The "locals.disableAds" variable can now be used to suppress rendering
80
- // of ads and 3rd party non-functional trackers.
81
-
82
- // The "locals.removePaywalls" variable can allow users to bypass pay-walled content.
83
- res.render('index.ejs');
84
- });
65
+ .use((req, res, next) => {
66
+ // X-Better-Web-Welcome header injection can could have it's own simple middleware like this:
67
+ res.set(getServerHeaderName(), getServerHeaderValue());
68
+
69
+ next();
70
+ })
71
+ .use((req, res, next) => {
72
+ const tokenContext = processRequest(req.get(getClientHeaderName()));
73
+ res.locals.tokenContext = tokenContext;
74
+
75
+ next();
76
+ })
77
+ .get("/", (req, res) => {
78
+ // The "locals.disableAds" variable can now be used to suppress rendering
79
+ // of ads and 3rd party non-functional trackers.
80
+
81
+ // If "locals.shouldRemoveAds" value is true, the ads should be disabled in the template.
82
+
83
+ // If "locals.shouldEnablePremiumContentAccess" value is true, the access to paywalled content should be enabled. Depending on site subscription pricing, the basic subscription access could be enabled without forcing visitor to pay.
84
+
85
+ // If "locals.shouldEnableVipExperience" value is true, the next tier subscription access should be enabled without forcing visitor to pay.
86
+ res.render("index.ejs");
87
+ });
85
88
 
86
89
  app.listen(port, () => {
87
90
  console.log(`Server listening at http://localhost:${port}`);
88
91
  });
89
92
  ```
90
93
 
91
- P.S.: Each web request coming from active subscriber using their Zero Ad Network browser extension will incur a fraction of CPU computation cost to verify the token data matches its encrypted signature. On modern web infrasctructure a request execution time will increase roughly by ~0.1ms to 3ms or so.
94
+ For more example implementations such as `Express.js`, `Hono` or `Fastify`, please go to [see more examples](https://github.com/laurynas-karvelis/zeroad-token/tree/main/examples/).
92
95
 
93
- In near future we will aim to add some form of "Request Header to processed result" caching mechanism for Redis users. In real life, Redis usually will deliver such payload slower than it would take to verify attached cryptographic token signature.
96
+ P.S.: Each web request coming from active subscriber using their Zero Ad Network browser extension will incur a tiny fraction of CPU computation cost to verify the token data matches its encrypted signature. On modern web infrasctructure a request execution time will increase roughly by ~0.08ms to 0.2ms or so. Mileage might vary, but the impact is minimal.
94
97
 
95
98
  # Final thoughts
96
99
 
@@ -21,16 +21,6 @@ var PROTOCOL_VERSION = /* @__PURE__ */ ((PROTOCOL_VERSION2) => {
21
21
  })(PROTOCOL_VERSION || {});
22
22
  const CURRENT_PROTOCOL_VERSION = 1 /* V_1 */;
23
23
 
24
- var constants = /*#__PURE__*/Object.freeze({
25
- __proto__: null,
26
- CLIENT_HEADERS: CLIENT_HEADERS,
27
- CURRENT_PROTOCOL_VERSION: CURRENT_PROTOCOL_VERSION,
28
- PROTOCOL_VERSION: PROTOCOL_VERSION,
29
- SERVER_HEADERS: SERVER_HEADERS,
30
- SITE_FEATURES: SITE_FEATURES,
31
- ZEROAD_NETWORK_PUBLIC_KEY: ZEROAD_NETWORK_PUBLIC_KEY
32
- });
33
-
34
24
  const toBase64 = (data) => {
35
25
  if (typeof data.toBase64 === "function") return data.toBase64();
36
26
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
@@ -161,7 +151,6 @@ exports.SITE_FEATURES = SITE_FEATURES;
161
151
  exports.ServerHeader = ServerHeader;
162
152
  exports.ZEROAD_NETWORK_PUBLIC_KEY = ZEROAD_NETWORK_PUBLIC_KEY;
163
153
  exports.bytesToUnixTimestamp = bytesToUnixTimestamp;
164
- exports.constants = constants;
165
154
  exports.fromBase64 = fromBase64;
166
155
  exports.hasFeature = hasFeature;
167
156
  exports.log = log;
@@ -19,16 +19,6 @@ var PROTOCOL_VERSION = /* @__PURE__ */ ((PROTOCOL_VERSION2) => {
19
19
  })(PROTOCOL_VERSION || {});
20
20
  const CURRENT_PROTOCOL_VERSION = 1 /* V_1 */;
21
21
 
22
- var constants = /*#__PURE__*/Object.freeze({
23
- __proto__: null,
24
- CLIENT_HEADERS: CLIENT_HEADERS,
25
- CURRENT_PROTOCOL_VERSION: CURRENT_PROTOCOL_VERSION,
26
- PROTOCOL_VERSION: PROTOCOL_VERSION,
27
- SERVER_HEADERS: SERVER_HEADERS,
28
- SITE_FEATURES: SITE_FEATURES,
29
- ZEROAD_NETWORK_PUBLIC_KEY: ZEROAD_NETWORK_PUBLIC_KEY
30
- });
31
-
32
22
  const toBase64 = (data) => {
33
23
  if (typeof data.toBase64 === "function") return data.toBase64();
34
24
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
@@ -151,4 +141,4 @@ class ServerHeader {
151
141
  }
152
142
  }
153
143
 
154
- export { CLIENT_HEADERS as C, PROTOCOL_VERSION as P, SITE_FEATURES as S, ZEROAD_NETWORK_PUBLIC_KEY as Z, ServerHeader as a, bytesToUnixTimestamp as b, setLogLevel as c, SERVER_HEADERS as d, CURRENT_PROTOCOL_VERSION as e, fromBase64 as f, constants as g, hasFeature as h, log as l, setFeatures as s, toBase64 as t, unixTimestampToBytes as u };
144
+ export { CLIENT_HEADERS as C, PROTOCOL_VERSION as P, SITE_FEATURES as S, ZEROAD_NETWORK_PUBLIC_KEY as Z, ServerHeader as a, bytesToUnixTimestamp as b, setLogLevel as c, SERVER_HEADERS as d, CURRENT_PROTOCOL_VERSION as e, fromBase64 as f, hasFeature as h, log as l, setFeatures as s, toBase64 as t, unixTimestampToBytes as u };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * This is an official ZeroAd Network public key.
3
+ * Used to verify `X-Better-Web-User` header values are not tampered with.
4
+ */
5
+ declare const ZEROAD_NETWORK_PUBLIC_KEY: string;
6
+ declare enum SITE_FEATURES {
7
+ ADLESS_EXPERIENCE = 1,
8
+ PREMIUM_CONTENT_ACCESS = 2,
9
+ VIP_EXPERIENCE = 4
10
+ }
11
+ type UUID = string;
12
+ declare enum SERVER_HEADERS {
13
+ WELCOME = "X-Better-Web-Welcome"
14
+ }
15
+ declare enum CLIENT_HEADERS {
16
+ HELLO = "X-Better-Web-Hello"
17
+ }
18
+ declare enum PROTOCOL_VERSION {
19
+ V_1 = 1
20
+ }
21
+ declare const CURRENT_PROTOCOL_VERSION = PROTOCOL_VERSION.V_1;
22
+ type ServerHeaderSimpleOptions = {
23
+ value: string;
24
+ };
25
+ type ServerHeaderExtendedOptions = {
26
+ siteId: UUID;
27
+ features: SITE_FEATURES[];
28
+ };
29
+ type ServerHeaderOptions = ServerHeaderExtendedOptions | ServerHeaderSimpleOptions;
30
+ type WelcomeHeaderParseResult = WelcomeHeader | undefined;
31
+ type WelcomeHeader = {
32
+ version: PROTOCOL_VERSION;
33
+ siteId: UUID;
34
+ flags: number;
35
+ };
36
+ type ClientHeaderParseResult = ClientParsedHeader | undefined;
37
+ type ClientParsedHeader = {
38
+ version: PROTOCOL_VERSION;
39
+ expiresAt: Date;
40
+ expired: boolean;
41
+ flags: number;
42
+ };
43
+
44
+ declare class ServerHeader {
45
+ name: SERVER_HEADERS;
46
+ value: string;
47
+ constructor(options: ServerHeaderOptions);
48
+ encode(siteId: UUID, features: SITE_FEATURES[]): string;
49
+ static decode(headerValue: string | undefined): WelcomeHeaderParseResult;
50
+ }
51
+
52
+ export { CLIENT_HEADERS, CURRENT_PROTOCOL_VERSION, PROTOCOL_VERSION, SERVER_HEADERS, SITE_FEATURES, ServerHeader, ZEROAD_NETWORK_PUBLIC_KEY };
53
+ export type { ClientHeaderParseResult, ClientParsedHeader, ServerHeaderExtendedOptions, ServerHeaderOptions, ServerHeaderSimpleOptions, UUID, WelcomeHeader, WelcomeHeaderParseResult };
@@ -1 +1,53 @@
1
- export { b as ServerHeader, j as constants } from './browser-DxDxgCTA.mjs';
1
+ /**
2
+ * This is an official ZeroAd Network public key.
3
+ * Used to verify `X-Better-Web-User` header values are not tampered with.
4
+ */
5
+ declare const ZEROAD_NETWORK_PUBLIC_KEY: string;
6
+ declare enum SITE_FEATURES {
7
+ ADLESS_EXPERIENCE = 1,
8
+ PREMIUM_CONTENT_ACCESS = 2,
9
+ VIP_EXPERIENCE = 4
10
+ }
11
+ type UUID = string;
12
+ declare enum SERVER_HEADERS {
13
+ WELCOME = "X-Better-Web-Welcome"
14
+ }
15
+ declare enum CLIENT_HEADERS {
16
+ HELLO = "X-Better-Web-Hello"
17
+ }
18
+ declare enum PROTOCOL_VERSION {
19
+ V_1 = 1
20
+ }
21
+ declare const CURRENT_PROTOCOL_VERSION = PROTOCOL_VERSION.V_1;
22
+ type ServerHeaderSimpleOptions = {
23
+ value: string;
24
+ };
25
+ type ServerHeaderExtendedOptions = {
26
+ siteId: UUID;
27
+ features: SITE_FEATURES[];
28
+ };
29
+ type ServerHeaderOptions = ServerHeaderExtendedOptions | ServerHeaderSimpleOptions;
30
+ type WelcomeHeaderParseResult = WelcomeHeader | undefined;
31
+ type WelcomeHeader = {
32
+ version: PROTOCOL_VERSION;
33
+ siteId: UUID;
34
+ flags: number;
35
+ };
36
+ type ClientHeaderParseResult = ClientParsedHeader | undefined;
37
+ type ClientParsedHeader = {
38
+ version: PROTOCOL_VERSION;
39
+ expiresAt: Date;
40
+ expired: boolean;
41
+ flags: number;
42
+ };
43
+
44
+ declare class ServerHeader {
45
+ name: SERVER_HEADERS;
46
+ value: string;
47
+ constructor(options: ServerHeaderOptions);
48
+ encode(siteId: UUID, features: SITE_FEATURES[]): string;
49
+ static decode(headerValue: string | undefined): WelcomeHeaderParseResult;
50
+ }
51
+
52
+ export { CLIENT_HEADERS, CURRENT_PROTOCOL_VERSION, PROTOCOL_VERSION, SERVER_HEADERS, SITE_FEATURES, ServerHeader, ZEROAD_NETWORK_PUBLIC_KEY };
53
+ export type { ClientHeaderParseResult, ClientParsedHeader, ServerHeaderExtendedOptions, ServerHeaderOptions, ServerHeaderSimpleOptions, UUID, WelcomeHeader, WelcomeHeaderParseResult };
package/dist/browser.mjs CHANGED
@@ -1 +1 @@
1
- export { a as ServerHeader, g as constants } from './browser-UaGP6C6U.mjs';
1
+ export { C as CLIENT_HEADERS, e as CURRENT_PROTOCOL_VERSION, P as PROTOCOL_VERSION, d as SERVER_HEADERS, S as SITE_FEATURES, a as ServerHeader, Z as ZEROAD_NETWORK_PUBLIC_KEY } from './browser-CX0ZDy3i.mjs';
package/dist/index.cjs CHANGED
@@ -1,40 +1,34 @@
1
1
  'use strict';
2
2
 
3
- var browser = require('./browser-BwYe5nvr.cjs');
3
+ var browser = require('./browser-BDaRPCd0.cjs');
4
+ var crypto = require('crypto');
4
5
 
5
- const cryptoUniversal = (() => {
6
- let cryptoImpl;
7
- if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
8
- cryptoImpl = globalThis.crypto;
9
- }
10
- if (!cryptoImpl) {
11
- try {
12
- const { webcrypto } = require("crypto");
13
- cryptoImpl = webcrypto;
14
- } catch {
15
- }
16
- }
17
- if (!cryptoImpl) {
18
- throw new Error("WebCrypto API not available in this environment.");
19
- }
20
- const getRandomValues = cryptoImpl.getRandomValues.bind(cryptoImpl);
21
- return {
22
- subtle: cryptoImpl.subtle,
23
- getRandomValues
24
- };
25
- })();
26
-
27
- const { subtle, getRandomValues } = cryptoUniversal;
28
- const algorithm = { name: "Ed25519" };
29
- const importPrivateKey = (privateKey) => subtle.importKey("pkcs8", browser.fromBase64(privateKey), algorithm, false, ["sign"]);
30
- const importPublicKey = (publicKey) => subtle.importKey("spki", browser.fromBase64(publicKey), algorithm, false, ["verify"]);
31
- const sign = (data, privateKey) => subtle.sign(algorithm, privateKey, data);
32
- const verify = (data, signature, publicKey) => subtle.verify(algorithm, publicKey, signature, data);
33
- const nonce = (byteCount) => {
34
- const bytes = new Uint8Array(byteCount);
35
- getRandomValues(bytes);
36
- return bytes;
6
+ const importPrivateKey = (privateKeyBase64) => {
7
+ const keyBuffer = Buffer.from(privateKeyBase64, "base64");
8
+ return crypto.createPrivateKey({
9
+ key: keyBuffer,
10
+ format: "der",
11
+ type: "pkcs8"
12
+ });
13
+ };
14
+ const importPublicKey = (publicKeyBase64) => {
15
+ const keyBuffer = Buffer.from(publicKeyBase64, "base64");
16
+ return crypto.createPublicKey({
17
+ key: keyBuffer,
18
+ format: "der",
19
+ type: "spki"
20
+ });
21
+ };
22
+ const sign = (data, privateKey) => {
23
+ const buffer = Buffer.from(data);
24
+ return crypto.sign(null, buffer, privateKey);
37
25
  };
26
+ const verify = (data, signature, publicKey) => {
27
+ const dataBuffer = Buffer.from(data);
28
+ const sigBuffer = Buffer.from(signature);
29
+ return crypto.verify(null, dataBuffer, publicKey, sigBuffer);
30
+ };
31
+ const nonce = (size) => new Uint8Array(crypto.randomBytes(size));
38
32
 
39
33
  const NONCE_BYTES = 4;
40
34
  const SEPARATOR = ".";
@@ -48,7 +42,7 @@ class ClientHeader {
48
42
  this.publicKey = publicKey;
49
43
  this.privateKey = privateKey;
50
44
  }
51
- async encode(version, expiresAt, features) {
45
+ encode(version, expiresAt, features) {
52
46
  if (!this.privateKey) throw new Error("Private key is required");
53
47
  const flags = browser.setFeatures(0, features);
54
48
  const data = mergeByteArrays([
@@ -57,18 +51,18 @@ class ClientHeader {
57
51
  browser.unixTimestampToBytes(expiresAt),
58
52
  new Uint8Array([flags])
59
53
  ]);
60
- if (!this.cryptoPrivateKey) this.cryptoPrivateKey = await importPrivateKey(this.privateKey);
61
- const signature = await sign(data.buffer, this.cryptoPrivateKey);
54
+ if (!this.cryptoPrivateKey) this.cryptoPrivateKey = importPrivateKey(this.privateKey);
55
+ const signature = sign(data.buffer, this.cryptoPrivateKey);
62
56
  return [browser.toBase64(data), browser.toBase64(new Uint8Array(signature))].join(SEPARATOR);
63
57
  }
64
- async decode(headerValue) {
58
+ decode(headerValue) {
65
59
  if (!headerValue?.length) return;
66
- if (!this.cryptoPublicKey) this.cryptoPublicKey = await importPublicKey(this.publicKey);
60
+ if (!this.cryptoPublicKey) this.cryptoPublicKey = importPublicKey(this.publicKey);
67
61
  try {
68
62
  const [data, signature] = headerValue.split(SEPARATOR);
69
63
  const dataBytes = browser.fromBase64(data);
70
64
  const signatureBytes = browser.fromBase64(signature);
71
- if (!await verify(dataBytes.buffer, signatureBytes.buffer, this.cryptoPublicKey)) {
65
+ if (!verify(dataBytes.buffer, signatureBytes.buffer, this.cryptoPublicKey)) {
72
66
  throw new Error("Forged header value is provided");
73
67
  }
74
68
  const version = dataBytes[0];
@@ -83,13 +77,19 @@ class ClientHeader {
83
77
  browser.log("warn", "Could not decode client header value", { reason: err?.message });
84
78
  }
85
79
  }
86
- async processRequest(headerValue) {
87
- const data = await this.decode(headerValue);
80
+ processRequest(headerValue) {
81
+ const data = this.decode(headerValue);
88
82
  return {
89
- data,
90
- shouldRemoveAds: () => shouldRemoveAds(data),
91
- shouldEnablePremiumContentAccess: () => shouldEnablePremiumContentAccess(data),
92
- shouldEnableVipExperience: () => shouldEnableVipExperience(data)
83
+ _raw: data,
84
+ get shouldRemoveAds() {
85
+ return shouldRemoveAds(data);
86
+ },
87
+ get shouldEnablePremiumContentAccess() {
88
+ return shouldEnablePremiumContentAccess(data);
89
+ },
90
+ get shouldEnableVipExperience() {
91
+ return shouldEnableVipExperience(data);
92
+ }
93
93
  };
94
94
  }
95
95
  }
@@ -118,12 +118,12 @@ class Site {
118
118
  this.clientHeader = new ClientHeader(browser.ZEROAD_NETWORK_PUBLIC_KEY);
119
119
  }
120
120
  }
121
- let _defaultSite;
122
- const init = (options) => _defaultSite = new Site(options);
123
- const processRequest = (headerValue) => _defaultSite.clientHeader.processRequest(headerValue);
124
- const getClientHeaderName = () => _defaultSite.clientHeader.name;
125
- const getServerHeaderName = () => _defaultSite.serverHeader.name;
126
- const getServerHeaderValue = () => _defaultSite.serverHeader.value;
121
+ let defaultSite;
122
+ const init = (options) => defaultSite = new Site(options);
123
+ const processRequest = (headerValue) => defaultSite.clientHeader.processRequest(headerValue);
124
+ const getClientHeaderName = () => defaultSite.clientHeader.name;
125
+ const getServerHeaderName = () => defaultSite.serverHeader.name;
126
+ const getServerHeaderValue = () => defaultSite.serverHeader.value;
127
127
 
128
128
  exports.CLIENT_HEADERS = browser.CLIENT_HEADERS;
129
129
  exports.CURRENT_PROTOCOL_VERSION = browser.CURRENT_PROTOCOL_VERSION;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CLIENT_HEADERS, P as PROTOCOL_VERSION, S as SITE_FEATURES, a as ClientHeaderParseResult, b as ServerHeader, c as ServerHeaderOptions, d as SERVER_HEADERS } from './browser-DxDxgCTA.cjs';
2
- export { e as CURRENT_PROTOCOL_VERSION, i as ClientParsedHeader, g as ServerHeaderExtendedOptions, f as ServerHeaderSimpleOptions, U as UUID, h as WelcomeHeader, W as WelcomeHeaderParseResult, Z as ZEROAD_NETWORK_PUBLIC_KEY } from './browser-DxDxgCTA.cjs';
1
+ import { CLIENT_HEADERS, PROTOCOL_VERSION, SITE_FEATURES, ClientHeaderParseResult, ServerHeader, ServerHeaderOptions, SERVER_HEADERS } from './browser.cjs';
2
+ export { CURRENT_PROTOCOL_VERSION, ClientParsedHeader, ServerHeaderExtendedOptions, ServerHeaderSimpleOptions, UUID, WelcomeHeader, WelcomeHeaderParseResult, ZEROAD_NETWORK_PUBLIC_KEY } from './browser.cjs';
3
3
 
4
4
  declare class ClientHeader {
5
5
  private cryptoPublicKey;
@@ -8,14 +8,14 @@ declare class ClientHeader {
8
8
  private privateKey;
9
9
  name: CLIENT_HEADERS;
10
10
  constructor(publicKey: string, privateKey?: string);
11
- encode(version: PROTOCOL_VERSION, expiresAt: Date, features: SITE_FEATURES[]): Promise<string>;
12
- decode(headerValue: string): Promise<ClientHeaderParseResult>;
13
- processRequest(headerValue: string | undefined): Promise<{
14
- data: ClientHeaderParseResult;
15
- shouldRemoveAds: () => boolean;
16
- shouldEnablePremiumContentAccess: () => boolean;
17
- shouldEnableVipExperience: () => boolean;
18
- }>;
11
+ encode(version: PROTOCOL_VERSION, expiresAt: Date, features: SITE_FEATURES[]): string;
12
+ decode(headerValue: string): ClientHeaderParseResult;
13
+ processRequest(headerValue: string | undefined): {
14
+ _raw: ClientHeaderParseResult;
15
+ readonly shouldRemoveAds: boolean;
16
+ readonly shouldEnablePremiumContentAccess: boolean;
17
+ readonly shouldEnableVipExperience: boolean;
18
+ };
19
19
  }
20
20
 
21
21
  type LogLevel = "error" | "warn" | "info" | "debug";
@@ -27,12 +27,12 @@ declare class Site {
27
27
  constructor(options: ServerHeaderOptions);
28
28
  }
29
29
  declare const init: (options: ServerHeaderOptions) => Site;
30
- declare const processRequest: (headerValue: string | undefined) => Promise<{
31
- data: ClientHeaderParseResult;
32
- shouldRemoveAds: () => boolean;
33
- shouldEnablePremiumContentAccess: () => boolean;
34
- shouldEnableVipExperience: () => boolean;
35
- }>;
30
+ declare const processRequest: (headerValue: string | undefined) => {
31
+ _raw: ClientHeaderParseResult;
32
+ readonly shouldRemoveAds: boolean;
33
+ readonly shouldEnablePremiumContentAccess: boolean;
34
+ readonly shouldEnableVipExperience: boolean;
35
+ };
36
36
  declare const getClientHeaderName: () => CLIENT_HEADERS;
37
37
  declare const getServerHeaderName: () => SERVER_HEADERS;
38
38
  declare const getServerHeaderValue: () => string;
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CLIENT_HEADERS, P as PROTOCOL_VERSION, S as SITE_FEATURES, a as ClientHeaderParseResult, b as ServerHeader, c as ServerHeaderOptions, d as SERVER_HEADERS } from './browser-DxDxgCTA.mjs';
2
- export { e as CURRENT_PROTOCOL_VERSION, i as ClientParsedHeader, g as ServerHeaderExtendedOptions, f as ServerHeaderSimpleOptions, U as UUID, h as WelcomeHeader, W as WelcomeHeaderParseResult, Z as ZEROAD_NETWORK_PUBLIC_KEY } from './browser-DxDxgCTA.mjs';
1
+ import { CLIENT_HEADERS, PROTOCOL_VERSION, SITE_FEATURES, ClientHeaderParseResult, ServerHeader, ServerHeaderOptions, SERVER_HEADERS } from './browser.mjs';
2
+ export { CURRENT_PROTOCOL_VERSION, ClientParsedHeader, ServerHeaderExtendedOptions, ServerHeaderSimpleOptions, UUID, WelcomeHeader, WelcomeHeaderParseResult, ZEROAD_NETWORK_PUBLIC_KEY } from './browser.mjs';
3
3
 
4
4
  declare class ClientHeader {
5
5
  private cryptoPublicKey;
@@ -8,14 +8,14 @@ declare class ClientHeader {
8
8
  private privateKey;
9
9
  name: CLIENT_HEADERS;
10
10
  constructor(publicKey: string, privateKey?: string);
11
- encode(version: PROTOCOL_VERSION, expiresAt: Date, features: SITE_FEATURES[]): Promise<string>;
12
- decode(headerValue: string): Promise<ClientHeaderParseResult>;
13
- processRequest(headerValue: string | undefined): Promise<{
14
- data: ClientHeaderParseResult;
15
- shouldRemoveAds: () => boolean;
16
- shouldEnablePremiumContentAccess: () => boolean;
17
- shouldEnableVipExperience: () => boolean;
18
- }>;
11
+ encode(version: PROTOCOL_VERSION, expiresAt: Date, features: SITE_FEATURES[]): string;
12
+ decode(headerValue: string): ClientHeaderParseResult;
13
+ processRequest(headerValue: string | undefined): {
14
+ _raw: ClientHeaderParseResult;
15
+ readonly shouldRemoveAds: boolean;
16
+ readonly shouldEnablePremiumContentAccess: boolean;
17
+ readonly shouldEnableVipExperience: boolean;
18
+ };
19
19
  }
20
20
 
21
21
  type LogLevel = "error" | "warn" | "info" | "debug";
@@ -27,12 +27,12 @@ declare class Site {
27
27
  constructor(options: ServerHeaderOptions);
28
28
  }
29
29
  declare const init: (options: ServerHeaderOptions) => Site;
30
- declare const processRequest: (headerValue: string | undefined) => Promise<{
31
- data: ClientHeaderParseResult;
32
- shouldRemoveAds: () => boolean;
33
- shouldEnablePremiumContentAccess: () => boolean;
34
- shouldEnableVipExperience: () => boolean;
35
- }>;
30
+ declare const processRequest: (headerValue: string | undefined) => {
31
+ _raw: ClientHeaderParseResult;
32
+ readonly shouldRemoveAds: boolean;
33
+ readonly shouldEnablePremiumContentAccess: boolean;
34
+ readonly shouldEnableVipExperience: boolean;
35
+ };
36
36
  declare const getClientHeaderName: () => CLIENT_HEADERS;
37
37
  declare const getServerHeaderName: () => SERVER_HEADERS;
38
38
  declare const getServerHeaderValue: () => string;
package/dist/index.mjs CHANGED
@@ -1,39 +1,33 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { f as fromBase64, C as CLIENT_HEADERS, s as setFeatures, u as unixTimestampToBytes, t as toBase64, P as PROTOCOL_VERSION, b as bytesToUnixTimestamp, l as log, S as SITE_FEATURES, h as hasFeature, a as ServerHeader, Z as ZEROAD_NETWORK_PUBLIC_KEY } from './browser-UaGP6C6U.mjs';
2
- export { e as CURRENT_PROTOCOL_VERSION, d as SERVER_HEADERS, c as setLogLevel } from './browser-UaGP6C6U.mjs';
1
+ import { C as CLIENT_HEADERS, s as setFeatures, u as unixTimestampToBytes, t as toBase64, f as fromBase64, P as PROTOCOL_VERSION, b as bytesToUnixTimestamp, l as log, S as SITE_FEATURES, h as hasFeature, a as ServerHeader, Z as ZEROAD_NETWORK_PUBLIC_KEY } from './browser-CX0ZDy3i.mjs';
2
+ export { e as CURRENT_PROTOCOL_VERSION, d as SERVER_HEADERS, c as setLogLevel } from './browser-CX0ZDy3i.mjs';
3
+ import { randomBytes, createPrivateKey, sign as sign$1, createPublicKey, verify as verify$1 } from 'crypto';
3
4
 
4
- const cryptoUniversal = (() => {
5
- let cryptoImpl;
6
- if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
7
- cryptoImpl = globalThis.crypto;
8
- }
9
- if (!cryptoImpl) {
10
- try {
11
- const { webcrypto } = require("crypto");
12
- cryptoImpl = webcrypto;
13
- } catch {
14
- }
15
- }
16
- if (!cryptoImpl) {
17
- throw new Error("WebCrypto API not available in this environment.");
18
- }
19
- const getRandomValues = cryptoImpl.getRandomValues.bind(cryptoImpl);
20
- return {
21
- subtle: cryptoImpl.subtle,
22
- getRandomValues
23
- };
24
- })();
25
-
26
- const { subtle, getRandomValues } = cryptoUniversal;
27
- const algorithm = { name: "Ed25519" };
28
- const importPrivateKey = (privateKey) => subtle.importKey("pkcs8", fromBase64(privateKey), algorithm, false, ["sign"]);
29
- const importPublicKey = (publicKey) => subtle.importKey("spki", fromBase64(publicKey), algorithm, false, ["verify"]);
30
- const sign = (data, privateKey) => subtle.sign(algorithm, privateKey, data);
31
- const verify = (data, signature, publicKey) => subtle.verify(algorithm, publicKey, signature, data);
32
- const nonce = (byteCount) => {
33
- const bytes = new Uint8Array(byteCount);
34
- getRandomValues(bytes);
35
- return bytes;
5
+ const importPrivateKey = (privateKeyBase64) => {
6
+ const keyBuffer = Buffer.from(privateKeyBase64, "base64");
7
+ return createPrivateKey({
8
+ key: keyBuffer,
9
+ format: "der",
10
+ type: "pkcs8"
11
+ });
12
+ };
13
+ const importPublicKey = (publicKeyBase64) => {
14
+ const keyBuffer = Buffer.from(publicKeyBase64, "base64");
15
+ return createPublicKey({
16
+ key: keyBuffer,
17
+ format: "der",
18
+ type: "spki"
19
+ });
20
+ };
21
+ const sign = (data, privateKey) => {
22
+ const buffer = Buffer.from(data);
23
+ return sign$1(null, buffer, privateKey);
36
24
  };
25
+ const verify = (data, signature, publicKey) => {
26
+ const dataBuffer = Buffer.from(data);
27
+ const sigBuffer = Buffer.from(signature);
28
+ return verify$1(null, dataBuffer, publicKey, sigBuffer);
29
+ };
30
+ const nonce = (size) => new Uint8Array(randomBytes(size));
37
31
 
38
32
  const NONCE_BYTES = 4;
39
33
  const SEPARATOR = ".";
@@ -47,7 +41,7 @@ class ClientHeader {
47
41
  this.publicKey = publicKey;
48
42
  this.privateKey = privateKey;
49
43
  }
50
- async encode(version, expiresAt, features) {
44
+ encode(version, expiresAt, features) {
51
45
  if (!this.privateKey) throw new Error("Private key is required");
52
46
  const flags = setFeatures(0, features);
53
47
  const data = mergeByteArrays([
@@ -56,18 +50,18 @@ class ClientHeader {
56
50
  unixTimestampToBytes(expiresAt),
57
51
  new Uint8Array([flags])
58
52
  ]);
59
- if (!this.cryptoPrivateKey) this.cryptoPrivateKey = await importPrivateKey(this.privateKey);
60
- const signature = await sign(data.buffer, this.cryptoPrivateKey);
53
+ if (!this.cryptoPrivateKey) this.cryptoPrivateKey = importPrivateKey(this.privateKey);
54
+ const signature = sign(data.buffer, this.cryptoPrivateKey);
61
55
  return [toBase64(data), toBase64(new Uint8Array(signature))].join(SEPARATOR);
62
56
  }
63
- async decode(headerValue) {
57
+ decode(headerValue) {
64
58
  if (!headerValue?.length) return;
65
- if (!this.cryptoPublicKey) this.cryptoPublicKey = await importPublicKey(this.publicKey);
59
+ if (!this.cryptoPublicKey) this.cryptoPublicKey = importPublicKey(this.publicKey);
66
60
  try {
67
61
  const [data, signature] = headerValue.split(SEPARATOR);
68
62
  const dataBytes = fromBase64(data);
69
63
  const signatureBytes = fromBase64(signature);
70
- if (!await verify(dataBytes.buffer, signatureBytes.buffer, this.cryptoPublicKey)) {
64
+ if (!verify(dataBytes.buffer, signatureBytes.buffer, this.cryptoPublicKey)) {
71
65
  throw new Error("Forged header value is provided");
72
66
  }
73
67
  const version = dataBytes[0];
@@ -82,13 +76,19 @@ class ClientHeader {
82
76
  log("warn", "Could not decode client header value", { reason: err?.message });
83
77
  }
84
78
  }
85
- async processRequest(headerValue) {
86
- const data = await this.decode(headerValue);
79
+ processRequest(headerValue) {
80
+ const data = this.decode(headerValue);
87
81
  return {
88
- data,
89
- shouldRemoveAds: () => shouldRemoveAds(data),
90
- shouldEnablePremiumContentAccess: () => shouldEnablePremiumContentAccess(data),
91
- shouldEnableVipExperience: () => shouldEnableVipExperience(data)
82
+ _raw: data,
83
+ get shouldRemoveAds() {
84
+ return shouldRemoveAds(data);
85
+ },
86
+ get shouldEnablePremiumContentAccess() {
87
+ return shouldEnablePremiumContentAccess(data);
88
+ },
89
+ get shouldEnableVipExperience() {
90
+ return shouldEnableVipExperience(data);
91
+ }
92
92
  };
93
93
  }
94
94
  }
@@ -117,11 +117,11 @@ class Site {
117
117
  this.clientHeader = new ClientHeader(ZEROAD_NETWORK_PUBLIC_KEY);
118
118
  }
119
119
  }
120
- let _defaultSite;
121
- const init = (options) => _defaultSite = new Site(options);
122
- const processRequest = (headerValue) => _defaultSite.clientHeader.processRequest(headerValue);
123
- const getClientHeaderName = () => _defaultSite.clientHeader.name;
124
- const getServerHeaderName = () => _defaultSite.serverHeader.name;
125
- const getServerHeaderValue = () => _defaultSite.serverHeader.value;
120
+ let defaultSite;
121
+ const init = (options) => defaultSite = new Site(options);
122
+ const processRequest = (headerValue) => defaultSite.clientHeader.processRequest(headerValue);
123
+ const getClientHeaderName = () => defaultSite.clientHeader.name;
124
+ const getServerHeaderName = () => defaultSite.serverHeader.name;
125
+ const getServerHeaderValue = () => defaultSite.serverHeader.value;
126
126
 
127
127
  export { CLIENT_HEADERS, ClientHeader, PROTOCOL_VERSION, SITE_FEATURES, ServerHeader, Site, ZEROAD_NETWORK_PUBLIC_KEY, getClientHeaderName, getServerHeaderName, getServerHeaderValue, init, processRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroad.network/token",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "repository": "github:laurynas-karvelis/zeroad-token",
6
6
  "homepage": "https://zeroad.network",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  "dependencies": {},
51
51
  "devDependencies": {
52
- "@types/bun": "^1.3.2",
52
+ "@types/bun": "^1.3.3",
53
53
  "@types/node": "^24.10.0",
54
54
  "pkgroll": "^2.20.1",
55
55
  "prettier": "^3.6.2",
@@ -1,76 +0,0 @@
1
- /**
2
- * This is an official ZeroAd Network public key.
3
- * Used to verify `X-Better-Web-User` header values are not tampered with.
4
- */
5
- declare const ZEROAD_NETWORK_PUBLIC_KEY: string;
6
- declare enum SITE_FEATURES {
7
- ADLESS_EXPERIENCE = 1,
8
- PREMIUM_CONTENT_ACCESS = 2,
9
- VIP_EXPERIENCE = 4
10
- }
11
- type UUID = string;
12
- declare enum SERVER_HEADERS {
13
- WELCOME = "X-Better-Web-Welcome"
14
- }
15
- declare enum CLIENT_HEADERS {
16
- HELLO = "X-Better-Web-Hello"
17
- }
18
- declare enum PROTOCOL_VERSION {
19
- V_1 = 1
20
- }
21
- declare const CURRENT_PROTOCOL_VERSION = PROTOCOL_VERSION.V_1;
22
- type ServerHeaderSimpleOptions = {
23
- value: string;
24
- };
25
- type ServerHeaderExtendedOptions = {
26
- siteId: UUID;
27
- features: SITE_FEATURES[];
28
- };
29
- type ServerHeaderOptions = ServerHeaderExtendedOptions | ServerHeaderSimpleOptions;
30
- type WelcomeHeaderParseResult = WelcomeHeader | undefined;
31
- type WelcomeHeader = {
32
- version: PROTOCOL_VERSION;
33
- siteId: UUID;
34
- flags: number;
35
- };
36
- type ClientHeaderParseResult = ClientParsedHeader | undefined;
37
- type ClientParsedHeader = {
38
- version: PROTOCOL_VERSION;
39
- expiresAt: Date;
40
- expired: boolean;
41
- flags: number;
42
- };
43
-
44
- type constants_CLIENT_HEADERS = CLIENT_HEADERS;
45
- declare const constants_CLIENT_HEADERS: typeof CLIENT_HEADERS;
46
- declare const constants_CURRENT_PROTOCOL_VERSION: typeof CURRENT_PROTOCOL_VERSION;
47
- type constants_ClientHeaderParseResult = ClientHeaderParseResult;
48
- type constants_ClientParsedHeader = ClientParsedHeader;
49
- type constants_PROTOCOL_VERSION = PROTOCOL_VERSION;
50
- declare const constants_PROTOCOL_VERSION: typeof PROTOCOL_VERSION;
51
- type constants_SERVER_HEADERS = SERVER_HEADERS;
52
- declare const constants_SERVER_HEADERS: typeof SERVER_HEADERS;
53
- type constants_SITE_FEATURES = SITE_FEATURES;
54
- declare const constants_SITE_FEATURES: typeof SITE_FEATURES;
55
- type constants_ServerHeaderExtendedOptions = ServerHeaderExtendedOptions;
56
- type constants_ServerHeaderOptions = ServerHeaderOptions;
57
- type constants_ServerHeaderSimpleOptions = ServerHeaderSimpleOptions;
58
- type constants_UUID = UUID;
59
- type constants_WelcomeHeader = WelcomeHeader;
60
- type constants_WelcomeHeaderParseResult = WelcomeHeaderParseResult;
61
- declare const constants_ZEROAD_NETWORK_PUBLIC_KEY: typeof ZEROAD_NETWORK_PUBLIC_KEY;
62
- declare namespace constants {
63
- export { constants_CLIENT_HEADERS as CLIENT_HEADERS, constants_CURRENT_PROTOCOL_VERSION as CURRENT_PROTOCOL_VERSION, constants_PROTOCOL_VERSION as PROTOCOL_VERSION, constants_SERVER_HEADERS as SERVER_HEADERS, constants_SITE_FEATURES as SITE_FEATURES, constants_ZEROAD_NETWORK_PUBLIC_KEY as ZEROAD_NETWORK_PUBLIC_KEY };
64
- export type { constants_ClientHeaderParseResult as ClientHeaderParseResult, constants_ClientParsedHeader as ClientParsedHeader, constants_ServerHeaderExtendedOptions as ServerHeaderExtendedOptions, constants_ServerHeaderOptions as ServerHeaderOptions, constants_ServerHeaderSimpleOptions as ServerHeaderSimpleOptions, constants_UUID as UUID, constants_WelcomeHeader as WelcomeHeader, constants_WelcomeHeaderParseResult as WelcomeHeaderParseResult };
65
- }
66
-
67
- declare class ServerHeader {
68
- name: SERVER_HEADERS;
69
- value: string;
70
- constructor(options: ServerHeaderOptions);
71
- encode(siteId: UUID, features: SITE_FEATURES[]): string;
72
- static decode(headerValue: string | undefined): WelcomeHeaderParseResult;
73
- }
74
-
75
- export { CLIENT_HEADERS as C, PROTOCOL_VERSION as P, SITE_FEATURES as S, ZEROAD_NETWORK_PUBLIC_KEY as Z, ServerHeader as b, SERVER_HEADERS as d, CURRENT_PROTOCOL_VERSION as e, constants as j };
76
- export type { UUID as U, WelcomeHeaderParseResult as W, ClientHeaderParseResult as a, ServerHeaderOptions as c, ServerHeaderSimpleOptions as f, ServerHeaderExtendedOptions as g, WelcomeHeader as h, ClientParsedHeader as i };
@@ -1,76 +0,0 @@
1
- /**
2
- * This is an official ZeroAd Network public key.
3
- * Used to verify `X-Better-Web-User` header values are not tampered with.
4
- */
5
- declare const ZEROAD_NETWORK_PUBLIC_KEY: string;
6
- declare enum SITE_FEATURES {
7
- ADLESS_EXPERIENCE = 1,
8
- PREMIUM_CONTENT_ACCESS = 2,
9
- VIP_EXPERIENCE = 4
10
- }
11
- type UUID = string;
12
- declare enum SERVER_HEADERS {
13
- WELCOME = "X-Better-Web-Welcome"
14
- }
15
- declare enum CLIENT_HEADERS {
16
- HELLO = "X-Better-Web-Hello"
17
- }
18
- declare enum PROTOCOL_VERSION {
19
- V_1 = 1
20
- }
21
- declare const CURRENT_PROTOCOL_VERSION = PROTOCOL_VERSION.V_1;
22
- type ServerHeaderSimpleOptions = {
23
- value: string;
24
- };
25
- type ServerHeaderExtendedOptions = {
26
- siteId: UUID;
27
- features: SITE_FEATURES[];
28
- };
29
- type ServerHeaderOptions = ServerHeaderExtendedOptions | ServerHeaderSimpleOptions;
30
- type WelcomeHeaderParseResult = WelcomeHeader | undefined;
31
- type WelcomeHeader = {
32
- version: PROTOCOL_VERSION;
33
- siteId: UUID;
34
- flags: number;
35
- };
36
- type ClientHeaderParseResult = ClientParsedHeader | undefined;
37
- type ClientParsedHeader = {
38
- version: PROTOCOL_VERSION;
39
- expiresAt: Date;
40
- expired: boolean;
41
- flags: number;
42
- };
43
-
44
- type constants_CLIENT_HEADERS = CLIENT_HEADERS;
45
- declare const constants_CLIENT_HEADERS: typeof CLIENT_HEADERS;
46
- declare const constants_CURRENT_PROTOCOL_VERSION: typeof CURRENT_PROTOCOL_VERSION;
47
- type constants_ClientHeaderParseResult = ClientHeaderParseResult;
48
- type constants_ClientParsedHeader = ClientParsedHeader;
49
- type constants_PROTOCOL_VERSION = PROTOCOL_VERSION;
50
- declare const constants_PROTOCOL_VERSION: typeof PROTOCOL_VERSION;
51
- type constants_SERVER_HEADERS = SERVER_HEADERS;
52
- declare const constants_SERVER_HEADERS: typeof SERVER_HEADERS;
53
- type constants_SITE_FEATURES = SITE_FEATURES;
54
- declare const constants_SITE_FEATURES: typeof SITE_FEATURES;
55
- type constants_ServerHeaderExtendedOptions = ServerHeaderExtendedOptions;
56
- type constants_ServerHeaderOptions = ServerHeaderOptions;
57
- type constants_ServerHeaderSimpleOptions = ServerHeaderSimpleOptions;
58
- type constants_UUID = UUID;
59
- type constants_WelcomeHeader = WelcomeHeader;
60
- type constants_WelcomeHeaderParseResult = WelcomeHeaderParseResult;
61
- declare const constants_ZEROAD_NETWORK_PUBLIC_KEY: typeof ZEROAD_NETWORK_PUBLIC_KEY;
62
- declare namespace constants {
63
- export { constants_CLIENT_HEADERS as CLIENT_HEADERS, constants_CURRENT_PROTOCOL_VERSION as CURRENT_PROTOCOL_VERSION, constants_PROTOCOL_VERSION as PROTOCOL_VERSION, constants_SERVER_HEADERS as SERVER_HEADERS, constants_SITE_FEATURES as SITE_FEATURES, constants_ZEROAD_NETWORK_PUBLIC_KEY as ZEROAD_NETWORK_PUBLIC_KEY };
64
- export type { constants_ClientHeaderParseResult as ClientHeaderParseResult, constants_ClientParsedHeader as ClientParsedHeader, constants_ServerHeaderExtendedOptions as ServerHeaderExtendedOptions, constants_ServerHeaderOptions as ServerHeaderOptions, constants_ServerHeaderSimpleOptions as ServerHeaderSimpleOptions, constants_UUID as UUID, constants_WelcomeHeader as WelcomeHeader, constants_WelcomeHeaderParseResult as WelcomeHeaderParseResult };
65
- }
66
-
67
- declare class ServerHeader {
68
- name: SERVER_HEADERS;
69
- value: string;
70
- constructor(options: ServerHeaderOptions);
71
- encode(siteId: UUID, features: SITE_FEATURES[]): string;
72
- static decode(headerValue: string | undefined): WelcomeHeaderParseResult;
73
- }
74
-
75
- export { CLIENT_HEADERS as C, PROTOCOL_VERSION as P, SITE_FEATURES as S, ZEROAD_NETWORK_PUBLIC_KEY as Z, ServerHeader as b, SERVER_HEADERS as d, CURRENT_PROTOCOL_VERSION as e, constants as j };
76
- export type { UUID as U, WelcomeHeaderParseResult as W, ClientHeaderParseResult as a, ServerHeaderOptions as c, ServerHeaderSimpleOptions as f, ServerHeaderExtendedOptions as g, WelcomeHeader as h, ClientParsedHeader as i };