@omni-co/embed 0.1.2 → 0.1.4

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.
@@ -0,0 +1,13 @@
1
+ type EmbedSsoProps = {
2
+ contentId: string;
3
+ domain?: string;
4
+ externalId: string;
5
+ name: string;
6
+ nonce?: string;
7
+ organizationName: string;
8
+ port?: number;
9
+ secret: string;
10
+ userAttributes?: Record<string, string>;
11
+ };
12
+ export declare const embedSsoDashboard: (props: EmbedSsoProps) => string;
13
+ export {};
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.embedSsoDashboard = void 0;
4
+ const random_str_1 = require("./random-str");
5
+ const signature_1 = require("./signature");
6
+ const defaultEmbedDomain = "embed-omniapp.co";
7
+ const embedLoginRoute = "/embed/login";
8
+ const embedDashboardPath = "/embed/dashboards";
9
+ const validateProps = (props) => {
10
+ const { contentId, externalId, name, nonce, organizationName, secret, userAttributes, } = props;
11
+ if (!contentId) {
12
+ throw new Error("contentId is required");
13
+ }
14
+ if (!externalId) {
15
+ throw new Error("externalId is required");
16
+ }
17
+ if (!name) {
18
+ throw new Error("name is required");
19
+ }
20
+ if (!organizationName) {
21
+ throw new Error("organizationName is required");
22
+ }
23
+ if (!secret) {
24
+ throw new Error("secret is required");
25
+ }
26
+ if (nonce && nonce.length !== 32) {
27
+ throw new Error("nonce must be 32 characters");
28
+ }
29
+ if (typeof userAttributes !== "object") {
30
+ if (userAttributes) {
31
+ throw new Error("userAttributes must be an object");
32
+ }
33
+ }
34
+ };
35
+ const embedSsoDashboard = (props) => {
36
+ validateProps(props);
37
+ let { contentId, domain, externalId, name, nonce, organizationName, port, secret, userAttributes: rawUserAttributes, } = props;
38
+ // Handle defaults
39
+ nonce = nonce ?? (0, random_str_1.random32ByteString)();
40
+ domain = domain ?? defaultEmbedDomain;
41
+ const userAttributes = rawUserAttributes && JSON.stringify(rawUserAttributes);
42
+ // Generate the url for the embed login route
43
+ const url = new URL(embedLoginRoute, `https://${organizationName.toLocaleLowerCase()}.${domain}${port ? `:${port}` : ""}`);
44
+ // Generate the content path
45
+ const contentPath = `${embedDashboardPath}/${contentId}`;
46
+ // Get a signature for the request
47
+ const signature = (0, signature_1.getSignature)({
48
+ loginUrl: url.toString(),
49
+ contentPath,
50
+ externalId,
51
+ name,
52
+ nonce,
53
+ secret,
54
+ userAttributes,
55
+ });
56
+ // Build and return the signed url
57
+ url.searchParams.append("contentPath", contentPath);
58
+ url.searchParams.append("externalId", externalId);
59
+ url.searchParams.append("name", name);
60
+ url.searchParams.append("nonce", nonce);
61
+ url.searchParams.append("signature", signature);
62
+ userAttributes && url.searchParams.append("userAttributes", userAttributes);
63
+ return url.toString();
64
+ };
65
+ exports.embedSsoDashboard = embedSsoDashboard;
@@ -0,0 +1,2 @@
1
+ export * from "./embed";
2
+ export * from "./signature";
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./embed"), exports);
18
+ __exportStar(require("./signature"), exports);
@@ -0,0 +1 @@
1
+ export declare const random32ByteString: (size?: number | undefined) => string;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.random32ByteString = void 0;
4
+ const nanoid_1 = require("nanoid");
5
+ const humanReadableByteSpace = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
6
+ // Generates a random 32 byte, human readable string.
7
+ // Based on math at https://zelark.github.io/nano-id-cc/
8
+ // at 1000 Ids/s it would take more than 1 quadrillion years or
9
+ // 8,730,800,738,924,245T IDs, in order to have a 1% probability
10
+ // of at least one collision.
11
+ exports.random32ByteString = (0, nanoid_1.customAlphabet)(humanReadableByteSpace, 32);
@@ -0,0 +1,39 @@
1
+ export declare const hmacSign: (data: string, secret: string) => string;
2
+ type SignatureProps = {
3
+ /**
4
+ * The protocol, domain, optional port and /embed/login route of the request.
5
+ *
6
+ * Example: `https://example.embed-omniapp.com/embed/login`
7
+ */
8
+ loginUrl: string;
9
+ /**
10
+ * The path to the content being embedded.
11
+ *
12
+ * Example: /embed/dashboards/123abc
13
+ */
14
+ contentPath: string;
15
+ /**
16
+ * The external id of the user.
17
+ */
18
+ externalId: string;
19
+ /**
20
+ * The name of the user.
21
+ */
22
+ name: string;
23
+ /**
24
+ * The nonce of the request.
25
+ */
26
+ nonce: string;
27
+ /**
28
+ * The secret used to sign the request
29
+ */
30
+ secret: string;
31
+ /**
32
+ * The user attributes to be sent with the request. Expected to be a stringified JSON object.
33
+ *
34
+ * Example: '{ "team": "Lakers" }'
35
+ */
36
+ userAttributes?: string;
37
+ };
38
+ export declare const getSignature: ({ loginUrl, contentPath, externalId, name, nonce, secret, userAttributes, }: SignatureProps) => string;
39
+ export {};
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getSignature = exports.hmacSign = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const hmacSign = (data, secret) => {
9
+ const hmac = crypto_1.default.createHmac("sha256", secret);
10
+ hmac.update(data);
11
+ return hmac.digest("base64url");
12
+ };
13
+ exports.hmacSign = hmacSign;
14
+ const getSignature = ({ loginUrl, contentPath, externalId, name, nonce, secret, userAttributes, }) => {
15
+ const validationStr = `
16
+ ${loginUrl}
17
+ ${contentPath}
18
+ ${externalId}
19
+ ${name}
20
+ ${nonce}
21
+ ${userAttributes}
22
+ `
23
+ .trim()
24
+ .replace(/\n\s+/g, "\n");
25
+ return (0, exports.hmacSign)(validationStr, secret);
26
+ };
27
+ exports.getSignature = getSignature;
@@ -0,0 +1,13 @@
1
+ type EmbedSsoProps = {
2
+ contentId: string;
3
+ domain?: string;
4
+ externalId: string;
5
+ name: string;
6
+ nonce?: string;
7
+ organizationName: string;
8
+ port?: number;
9
+ secret: string;
10
+ userAttributes?: Record<string, string>;
11
+ };
12
+ export declare const embedSsoDashboard: (props: EmbedSsoProps) => string;
13
+ export {};
@@ -0,0 +1,61 @@
1
+ import { random32ByteString } from "./random-str";
2
+ import { getSignature } from "./signature";
3
+ const defaultEmbedDomain = "embed-omniapp.co";
4
+ const embedLoginRoute = "/embed/login";
5
+ const embedDashboardPath = "/embed/dashboards";
6
+ const validateProps = (props) => {
7
+ const { contentId, externalId, name, nonce, organizationName, secret, userAttributes, } = props;
8
+ if (!contentId) {
9
+ throw new Error("contentId is required");
10
+ }
11
+ if (!externalId) {
12
+ throw new Error("externalId is required");
13
+ }
14
+ if (!name) {
15
+ throw new Error("name is required");
16
+ }
17
+ if (!organizationName) {
18
+ throw new Error("organizationName is required");
19
+ }
20
+ if (!secret) {
21
+ throw new Error("secret is required");
22
+ }
23
+ if (nonce && nonce.length !== 32) {
24
+ throw new Error("nonce must be 32 characters");
25
+ }
26
+ if (typeof userAttributes !== "object") {
27
+ if (userAttributes) {
28
+ throw new Error("userAttributes must be an object");
29
+ }
30
+ }
31
+ };
32
+ export const embedSsoDashboard = (props) => {
33
+ validateProps(props);
34
+ let { contentId, domain, externalId, name, nonce, organizationName, port, secret, userAttributes: rawUserAttributes, } = props;
35
+ // Handle defaults
36
+ nonce = nonce ?? random32ByteString();
37
+ domain = domain ?? defaultEmbedDomain;
38
+ const userAttributes = rawUserAttributes && JSON.stringify(rawUserAttributes);
39
+ // Generate the url for the embed login route
40
+ const url = new URL(embedLoginRoute, `https://${organizationName.toLocaleLowerCase()}.${domain}${port ? `:${port}` : ""}`);
41
+ // Generate the content path
42
+ const contentPath = `${embedDashboardPath}/${contentId}`;
43
+ // Get a signature for the request
44
+ const signature = getSignature({
45
+ loginUrl: url.toString(),
46
+ contentPath,
47
+ externalId,
48
+ name,
49
+ nonce,
50
+ secret,
51
+ userAttributes,
52
+ });
53
+ // Build and return the signed url
54
+ url.searchParams.append("contentPath", contentPath);
55
+ url.searchParams.append("externalId", externalId);
56
+ url.searchParams.append("name", name);
57
+ url.searchParams.append("nonce", nonce);
58
+ url.searchParams.append("signature", signature);
59
+ userAttributes && url.searchParams.append("userAttributes", userAttributes);
60
+ return url.toString();
61
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./embed";
2
+ export * from "./signature";
@@ -0,0 +1,2 @@
1
+ export * from "./embed";
2
+ export * from "./signature";
@@ -0,0 +1 @@
1
+ export declare const random32ByteString: (size?: number | undefined) => string;
@@ -0,0 +1,8 @@
1
+ import { customAlphabet } from "nanoid";
2
+ const humanReadableByteSpace = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
3
+ // Generates a random 32 byte, human readable string.
4
+ // Based on math at https://zelark.github.io/nano-id-cc/
5
+ // at 1000 Ids/s it would take more than 1 quadrillion years or
6
+ // 8,730,800,738,924,245T IDs, in order to have a 1% probability
7
+ // of at least one collision.
8
+ export const random32ByteString = customAlphabet(humanReadableByteSpace, 32);
@@ -0,0 +1,39 @@
1
+ export declare const hmacSign: (data: string, secret: string) => string;
2
+ type SignatureProps = {
3
+ /**
4
+ * The protocol, domain, optional port and /embed/login route of the request.
5
+ *
6
+ * Example: `https://example.embed-omniapp.com/embed/login`
7
+ */
8
+ loginUrl: string;
9
+ /**
10
+ * The path to the content being embedded.
11
+ *
12
+ * Example: /embed/dashboards/123abc
13
+ */
14
+ contentPath: string;
15
+ /**
16
+ * The external id of the user.
17
+ */
18
+ externalId: string;
19
+ /**
20
+ * The name of the user.
21
+ */
22
+ name: string;
23
+ /**
24
+ * The nonce of the request.
25
+ */
26
+ nonce: string;
27
+ /**
28
+ * The secret used to sign the request
29
+ */
30
+ secret: string;
31
+ /**
32
+ * The user attributes to be sent with the request. Expected to be a stringified JSON object.
33
+ *
34
+ * Example: '{ "team": "Lakers" }'
35
+ */
36
+ userAttributes?: string;
37
+ };
38
+ export declare const getSignature: ({ loginUrl, contentPath, externalId, name, nonce, secret, userAttributes, }: SignatureProps) => string;
39
+ export {};
@@ -0,0 +1,19 @@
1
+ import crypto from "crypto";
2
+ export const hmacSign = (data, secret) => {
3
+ const hmac = crypto.createHmac("sha256", secret);
4
+ hmac.update(data);
5
+ return hmac.digest("base64url");
6
+ };
7
+ export const getSignature = ({ loginUrl, contentPath, externalId, name, nonce, secret, userAttributes, }) => {
8
+ const validationStr = `
9
+ ${loginUrl}
10
+ ${contentPath}
11
+ ${externalId}
12
+ ${name}
13
+ ${nonce}
14
+ ${userAttributes}
15
+ `
16
+ .trim()
17
+ .replace(/\n\s+/g, "\n");
18
+ return hmacSign(validationStr, secret);
19
+ };
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
- "version": "0.1.2",
2
+ "version": "0.1.4",
3
3
  "license": "MIT",
4
4
  "name": "@omni-co/embed",
5
5
  "author": "Nate Agrin <nate@exploreomni.com>",
6
6
  "main": "lib/cjs/index.js",
7
7
  "module": "lib/esm/index.js",
8
8
  "files": [
9
- "lib/"
9
+ "lib/**/*"
10
10
  ],
11
- "prepublishOnly": "npm run build",
12
11
  "devDependencies": {
13
12
  "@types/node": "^20.8.9",
14
13
  "typescript": "^5.2.2",
@@ -17,6 +16,7 @@
17
16
  "scripts": {
18
17
  "build": "npm run clean && tsc -p tsconfig.json && tsc -p tsconfig.cjs.json",
19
18
  "clean": "rm -rf lib",
19
+ "prepublishOnly": "npm run build",
20
20
  "test": "vitest"
21
21
  },
22
22
  "dependencies": {