@unclick/mcp-server 0.2.4 → 0.2.5
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/dist/algolia-tool.d.ts +5 -0
- package/dist/algolia-tool.d.ts.map +1 -0
- package/dist/algolia-tool.js +121 -0
- package/dist/algolia-tool.js.map +1 -0
- package/dist/assemblyai-tool.d.ts +7 -0
- package/dist/assemblyai-tool.d.ts.map +1 -0
- package/dist/assemblyai-tool.js +127 -0
- package/dist/assemblyai-tool.js.map +1 -0
- package/dist/circleci-tool.d.ts +7 -0
- package/dist/circleci-tool.d.ts.map +1 -0
- package/dist/circleci-tool.js +133 -0
- package/dist/circleci-tool.js.map +1 -0
- package/dist/cohere-tool.d.ts +7 -0
- package/dist/cohere-tool.d.ts.map +1 -0
- package/dist/cohere-tool.js +225 -0
- package/dist/cohere-tool.js.map +1 -0
- package/dist/convertkit-tool.d.ts +7 -0
- package/dist/convertkit-tool.d.ts.map +1 -0
- package/dist/convertkit-tool.js +213 -0
- package/dist/convertkit-tool.js.map +1 -0
- package/dist/datadog-tool.d.ts +7 -0
- package/dist/datadog-tool.d.ts.map +1 -0
- package/dist/datadog-tool.js +121 -0
- package/dist/datadog-tool.js.map +1 -0
- package/dist/deepl-tool.d.ts +5 -0
- package/dist/deepl-tool.d.ts.map +1 -0
- package/dist/deepl-tool.js +137 -0
- package/dist/deepl-tool.js.map +1 -0
- package/dist/flyio-tool.d.ts +6 -0
- package/dist/flyio-tool.d.ts.map +1 -0
- package/dist/flyio-tool.js +158 -0
- package/dist/flyio-tool.js.map +1 -0
- package/dist/groq-tool.d.ts +3 -0
- package/dist/groq-tool.d.ts.map +1 -0
- package/dist/groq-tool.js +109 -0
- package/dist/groq-tool.js.map +1 -0
- package/dist/gumroad-tool.d.ts +6 -0
- package/dist/gumroad-tool.d.ts.map +1 -0
- package/dist/gumroad-tool.js +90 -0
- package/dist/gumroad-tool.js.map +1 -0
- package/dist/heygen-tool.d.ts +5 -0
- package/dist/heygen-tool.d.ts.map +1 -0
- package/dist/heygen-tool.js +134 -0
- package/dist/heygen-tool.js.map +1 -0
- package/dist/higgsfield-tool.d.ts +5 -0
- package/dist/higgsfield-tool.d.ts.map +1 -0
- package/dist/higgsfield-tool.js +120 -0
- package/dist/higgsfield-tool.js.map +1 -0
- package/dist/keychain-crypto.d.ts +24 -0
- package/dist/keychain-crypto.d.ts.map +1 -0
- package/dist/keychain-crypto.js +60 -0
- package/dist/keychain-crypto.js.map +1 -0
- package/dist/keychain-secure-input.d.ts +17 -0
- package/dist/keychain-secure-input.d.ts.map +1 -0
- package/dist/keychain-secure-input.js +229 -0
- package/dist/keychain-secure-input.js.map +1 -0
- package/dist/keychain-tool.d.ts +3 -0
- package/dist/keychain-tool.d.ts.map +1 -0
- package/dist/keychain-tool.js +516 -0
- package/dist/keychain-tool.js.map +1 -0
- package/dist/kling-tool.d.ts +3 -0
- package/dist/kling-tool.d.ts.map +1 -0
- package/dist/kling-tool.js +102 -0
- package/dist/kling-tool.js.map +1 -0
- package/dist/lemonsqueezy-tool.d.ts +7 -0
- package/dist/lemonsqueezy-tool.d.ts.map +1 -0
- package/dist/lemonsqueezy-tool.js +220 -0
- package/dist/lemonsqueezy-tool.js.map +1 -0
- package/dist/local-catalog-handlers.d.ts +3 -0
- package/dist/local-catalog-handlers.d.ts.map +1 -0
- package/dist/local-catalog-handlers.js +1254 -0
- package/dist/local-catalog-handlers.js.map +1 -0
- package/dist/mailchimp-tool.d.ts +8 -0
- package/dist/mailchimp-tool.d.ts.map +1 -0
- package/dist/mailchimp-tool.js +138 -0
- package/dist/mailchimp-tool.js.map +1 -0
- package/dist/mapbox-tool.d.ts +6 -0
- package/dist/mapbox-tool.d.ts.map +1 -0
- package/dist/mapbox-tool.js +106 -0
- package/dist/mapbox-tool.js.map +1 -0
- package/dist/mistral-tool.d.ts +4 -0
- package/dist/mistral-tool.d.ts.map +1 -0
- package/dist/mistral-tool.js +145 -0
- package/dist/mistral-tool.js.map +1 -0
- package/dist/mixpanel-tool.d.ts +6 -0
- package/dist/mixpanel-tool.d.ts.map +1 -0
- package/dist/mixpanel-tool.js +162 -0
- package/dist/mixpanel-tool.js.map +1 -0
- package/dist/neon-tool.d.ts +7 -0
- package/dist/neon-tool.d.ts.map +1 -0
- package/dist/neon-tool.js +156 -0
- package/dist/neon-tool.js.map +1 -0
- package/dist/pagerduty-tool.d.ts +8 -0
- package/dist/pagerduty-tool.d.ts.map +1 -0
- package/dist/pagerduty-tool.js +185 -0
- package/dist/pagerduty-tool.js.map +1 -0
- package/dist/perplexity-tool.d.ts +2 -0
- package/dist/perplexity-tool.d.ts.map +1 -0
- package/dist/perplexity-tool.js +93 -0
- package/dist/perplexity-tool.js.map +1 -0
- package/dist/pika-tool.d.ts +4 -0
- package/dist/pika-tool.d.ts.map +1 -0
- package/dist/pika-tool.js +102 -0
- package/dist/pika-tool.js.map +1 -0
- package/dist/pinecone-tool.d.ts +6 -0
- package/dist/pinecone-tool.d.ts.map +1 -0
- package/dist/pinecone-tool.js +148 -0
- package/dist/pinecone-tool.js.map +1 -0
- package/dist/postmark-tool.d.ts +7 -0
- package/dist/postmark-tool.d.ts.map +1 -0
- package/dist/postmark-tool.js +148 -0
- package/dist/postmark-tool.js.map +1 -0
- package/dist/qc-tool.d.ts +4 -0
- package/dist/qc-tool.d.ts.map +1 -0
- package/dist/qc-tool.js +415 -0
- package/dist/qc-tool.js.map +1 -0
- package/dist/render-tool.d.ts +7 -0
- package/dist/render-tool.d.ts.map +1 -0
- package/dist/render-tool.js +158 -0
- package/dist/render-tool.js.map +1 -0
- package/dist/runway-tool.d.ts +4 -0
- package/dist/runway-tool.d.ts.map +1 -0
- package/dist/runway-tool.js +110 -0
- package/dist/runway-tool.js.map +1 -0
- package/dist/segment-tool.d.ts +6 -0
- package/dist/segment-tool.d.ts.map +1 -0
- package/dist/segment-tool.js +129 -0
- package/dist/segment-tool.js.map +1 -0
- package/dist/sendgrid-tool.d.ts +7 -0
- package/dist/sendgrid-tool.d.ts.map +1 -0
- package/dist/sendgrid-tool.js +124 -0
- package/dist/sendgrid-tool.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -0
- package/dist/server.js.map +1 -1
- package/dist/togetherai-tool.d.ts +5 -0
- package/dist/togetherai-tool.d.ts.map +1 -0
- package/dist/togetherai-tool.js +129 -0
- package/dist/togetherai-tool.js.map +1 -0
- package/dist/tool-wiring.d.ts +4608 -692
- package/dist/tool-wiring.d.ts.map +1 -1
- package/dist/tool-wiring.js +2946 -463
- package/dist/tool-wiring.js.map +1 -1
- package/dist/turso-tool.d.ts +6 -0
- package/dist/turso-tool.d.ts.map +1 -0
- package/dist/turso-tool.js +158 -0
- package/dist/turso-tool.js.map +1 -0
- package/dist/upstash-tool.d.ts +8 -0
- package/dist/upstash-tool.d.ts.map +1 -0
- package/dist/upstash-tool.js +191 -0
- package/dist/upstash-tool.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// HeyGen API integration for the UnClick MCP server.
|
|
2
|
+
// Uses the HeyGen REST API via fetch - no external dependencies.
|
|
3
|
+
// Users must supply an API key from app.heygen.com/settings.
|
|
4
|
+
const HG_API_BASE = "https://api.heygen.com";
|
|
5
|
+
// ─── Auth validation ──────────────────────────────────────────────────────────
|
|
6
|
+
function requireKey(args) {
|
|
7
|
+
const key = String(args.api_key ?? "").trim();
|
|
8
|
+
if (!key)
|
|
9
|
+
throw new Error("api_key is required. Get one at app.heygen.com/settings.");
|
|
10
|
+
return key;
|
|
11
|
+
}
|
|
12
|
+
// ─── API helpers ──────────────────────────────────────────────────────────────
|
|
13
|
+
async function hgGet(apiKey, path) {
|
|
14
|
+
const res = await fetch(`${HG_API_BASE}${path}`, {
|
|
15
|
+
headers: {
|
|
16
|
+
"x-api-key": apiKey,
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const data = await res.json();
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
const msg = data.message ?? data.error ?? `HTTP ${res.status}`;
|
|
23
|
+
throw new Error(`HeyGen error (${res.status}): ${msg}`);
|
|
24
|
+
}
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
async function hgPost(apiKey, path, body) {
|
|
28
|
+
const res = await fetch(`${HG_API_BASE}${path}`, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: {
|
|
31
|
+
"x-api-key": apiKey,
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify(body),
|
|
35
|
+
});
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const msg = data.message ?? data.error ?? `HTTP ${res.status}`;
|
|
39
|
+
throw new Error(`HeyGen error (${res.status}): ${msg}`);
|
|
40
|
+
}
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
43
|
+
// ─── Operations ───────────────────────────────────────────────────────────────
|
|
44
|
+
export async function heygen_create_avatar_video(args) {
|
|
45
|
+
const apiKey = requireKey(args);
|
|
46
|
+
const avatarId = String(args.avatar_id ?? "").trim();
|
|
47
|
+
const script = String(args.script ?? "").trim();
|
|
48
|
+
if (!avatarId)
|
|
49
|
+
throw new Error("avatar_id is required.");
|
|
50
|
+
if (!script)
|
|
51
|
+
throw new Error("script is required (the text the avatar will speak).");
|
|
52
|
+
const voiceId = args.voice_id ? String(args.voice_id) : undefined;
|
|
53
|
+
const backgroundUrl = args.background_url ? String(args.background_url) : undefined;
|
|
54
|
+
const width = args.width ? Number(args.width) : 1280;
|
|
55
|
+
const height = args.height ? Number(args.height) : 720;
|
|
56
|
+
const body = {
|
|
57
|
+
video_inputs: [
|
|
58
|
+
{
|
|
59
|
+
character: {
|
|
60
|
+
type: "avatar",
|
|
61
|
+
avatar_id: avatarId,
|
|
62
|
+
avatar_style: args.avatar_style ?? "normal",
|
|
63
|
+
},
|
|
64
|
+
voice: voiceId
|
|
65
|
+
? { type: "text", input_text: script, voice_id: voiceId }
|
|
66
|
+
: { type: "text", input_text: script },
|
|
67
|
+
background: backgroundUrl
|
|
68
|
+
? { type: "image", url: backgroundUrl }
|
|
69
|
+
: { type: "color", value: "#ffffff" },
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
dimension: { width, height },
|
|
73
|
+
};
|
|
74
|
+
if (args.title)
|
|
75
|
+
body.title = String(args.title);
|
|
76
|
+
if (args.test !== undefined)
|
|
77
|
+
body.test = Boolean(args.test);
|
|
78
|
+
const result = await hgPost(apiKey, "/v2/video/generate", body);
|
|
79
|
+
const videoId = (result.data?.video_id ?? result.video_id);
|
|
80
|
+
return {
|
|
81
|
+
video_id: videoId ?? null,
|
|
82
|
+
status: "submitted",
|
|
83
|
+
note: "Use heygen_get_video_status with the video_id to poll for completion.",
|
|
84
|
+
raw: result,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export async function heygen_list_avatars(args) {
|
|
88
|
+
const apiKey = requireKey(args);
|
|
89
|
+
const data = await hgGet(apiKey, "/v2/avatars");
|
|
90
|
+
const avatars = data.data?.avatars ?? [];
|
|
91
|
+
return {
|
|
92
|
+
count: avatars.length,
|
|
93
|
+
avatars: avatars.map((a) => ({
|
|
94
|
+
avatar_id: a.avatar_id,
|
|
95
|
+
name: a.avatar_name,
|
|
96
|
+
gender: a.gender ?? null,
|
|
97
|
+
preview_image_url: a.preview_image_url ?? null,
|
|
98
|
+
})),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export async function heygen_get_video_status(args) {
|
|
102
|
+
const apiKey = requireKey(args);
|
|
103
|
+
const videoId = String(args.video_id ?? "").trim();
|
|
104
|
+
if (!videoId)
|
|
105
|
+
throw new Error("video_id is required.");
|
|
106
|
+
const data = await hgGet(apiKey, `/v1/video_status.get?video_id=${encodeURIComponent(videoId)}`);
|
|
107
|
+
const info = data.data ?? data;
|
|
108
|
+
return {
|
|
109
|
+
video_id: videoId,
|
|
110
|
+
status: info.status ?? null,
|
|
111
|
+
video_url: info.video_url ?? null,
|
|
112
|
+
thumbnail_url: info.thumbnail_url ?? null,
|
|
113
|
+
duration: info.duration ?? null,
|
|
114
|
+
created_at: info.created_at ?? null,
|
|
115
|
+
error: info.error ?? null,
|
|
116
|
+
raw: data,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
export async function heygen_list_voices(args) {
|
|
120
|
+
const apiKey = requireKey(args);
|
|
121
|
+
const data = await hgGet(apiKey, "/v2/voices");
|
|
122
|
+
const voices = data.data?.voices ?? [];
|
|
123
|
+
return {
|
|
124
|
+
count: voices.length,
|
|
125
|
+
voices: voices.map((v) => ({
|
|
126
|
+
voice_id: v.voice_id,
|
|
127
|
+
name: v.name,
|
|
128
|
+
language: v.language,
|
|
129
|
+
gender: v.gender,
|
|
130
|
+
preview_audio: v.preview_audio ?? null,
|
|
131
|
+
})),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=heygen-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heygen-tool.js","sourceRoot":"","sources":["../src/heygen-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function higgsfield_generate_video(args: Record<string, unknown>): Promise<unknown>;
|
|
2
|
+
export declare function higgsfield_generate_image(args: Record<string, unknown>): Promise<unknown>;
|
|
3
|
+
export declare function higgsfield_get_styles(args: Record<string, unknown>): Promise<unknown>;
|
|
4
|
+
export declare function higgsfield_get_status(args: Record<string, unknown>): Promise<unknown>;
|
|
5
|
+
//# sourceMappingURL=higgsfield-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"higgsfield-tool.d.ts","sourceRoot":"","sources":["../src/higgsfield-tool.ts"],"names":[],"mappings":"AAoDA,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAqB/F;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAqB/F;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAS3F;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB3F"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Higgsfield AI API integration for the UnClick MCP server.
|
|
2
|
+
// Uses the Higgsfield REST API via fetch - no external dependencies.
|
|
3
|
+
// Users must supply an API key from higgsfield.ai.
|
|
4
|
+
const HF_API_BASE = "https://api.higgsfield.ai/v1";
|
|
5
|
+
// ─── Auth validation ──────────────────────────────────────────────────────────
|
|
6
|
+
function requireKey(args) {
|
|
7
|
+
const key = String(args.api_key ?? "").trim();
|
|
8
|
+
if (!key)
|
|
9
|
+
throw new Error("api_key is required. Get one at higgsfield.ai.");
|
|
10
|
+
return key;
|
|
11
|
+
}
|
|
12
|
+
// ─── API helpers ──────────────────────────────────────────────────────────────
|
|
13
|
+
async function hfGet(apiKey, path) {
|
|
14
|
+
const res = await fetch(`${HF_API_BASE}${path}`, {
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: `Bearer ${apiKey}`,
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const data = await res.json();
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
const msg = data.message ?? data.error ?? `HTTP ${res.status}`;
|
|
23
|
+
throw new Error(`Higgsfield error (${res.status}): ${msg}`);
|
|
24
|
+
}
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
async function hfPost(apiKey, path, body) {
|
|
28
|
+
const res = await fetch(`${HF_API_BASE}${path}`, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: `Bearer ${apiKey}`,
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify(body),
|
|
35
|
+
});
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const msg = data.message ?? data.error ?? `HTTP ${res.status}`;
|
|
39
|
+
throw new Error(`Higgsfield error (${res.status}): ${msg}`);
|
|
40
|
+
}
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
43
|
+
// ─── Operations ───────────────────────────────────────────────────────────────
|
|
44
|
+
export async function higgsfield_generate_video(args) {
|
|
45
|
+
const apiKey = requireKey(args);
|
|
46
|
+
const prompt = String(args.prompt ?? "").trim();
|
|
47
|
+
if (!prompt)
|
|
48
|
+
throw new Error("prompt is required.");
|
|
49
|
+
const body = { prompt };
|
|
50
|
+
if (args.style)
|
|
51
|
+
body.style = String(args.style);
|
|
52
|
+
if (args.duration)
|
|
53
|
+
body.duration = Number(args.duration);
|
|
54
|
+
if (args.aspect_ratio)
|
|
55
|
+
body.aspect_ratio = String(args.aspect_ratio);
|
|
56
|
+
if (args.negative_prompt)
|
|
57
|
+
body.negative_prompt = String(args.negative_prompt);
|
|
58
|
+
if (args.seed !== undefined)
|
|
59
|
+
body.seed = Number(args.seed);
|
|
60
|
+
const result = await hfPost(apiKey, "/video/generate", body);
|
|
61
|
+
return {
|
|
62
|
+
generation_id: result.id ?? result.generation_id ?? null,
|
|
63
|
+
status: result.status ?? "submitted",
|
|
64
|
+
prompt,
|
|
65
|
+
note: "Use higgsfield_get_status with the generation_id to poll for completion.",
|
|
66
|
+
raw: result,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export async function higgsfield_generate_image(args) {
|
|
70
|
+
const apiKey = requireKey(args);
|
|
71
|
+
const prompt = String(args.prompt ?? "").trim();
|
|
72
|
+
if (!prompt)
|
|
73
|
+
throw new Error("prompt is required.");
|
|
74
|
+
const body = { prompt };
|
|
75
|
+
if (args.style)
|
|
76
|
+
body.style = String(args.style);
|
|
77
|
+
if (args.width)
|
|
78
|
+
body.width = Number(args.width);
|
|
79
|
+
if (args.height)
|
|
80
|
+
body.height = Number(args.height);
|
|
81
|
+
if (args.negative_prompt)
|
|
82
|
+
body.negative_prompt = String(args.negative_prompt);
|
|
83
|
+
if (args.seed !== undefined)
|
|
84
|
+
body.seed = Number(args.seed);
|
|
85
|
+
const result = await hfPost(apiKey, "/image/generate", body);
|
|
86
|
+
return {
|
|
87
|
+
generation_id: result.id ?? result.generation_id ?? null,
|
|
88
|
+
status: result.status ?? "submitted",
|
|
89
|
+
image_url: result.image_url ?? result.url ?? null,
|
|
90
|
+
prompt,
|
|
91
|
+
raw: result,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export async function higgsfield_get_styles(args) {
|
|
95
|
+
const apiKey = requireKey(args);
|
|
96
|
+
const data = await hfGet(apiKey, "/styles");
|
|
97
|
+
const styles = data.styles ?? data.data ?? [];
|
|
98
|
+
return {
|
|
99
|
+
count: Array.isArray(styles) ? styles.length : 0,
|
|
100
|
+
styles,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export async function higgsfield_get_status(args) {
|
|
104
|
+
const apiKey = requireKey(args);
|
|
105
|
+
const generationId = String(args.generation_id ?? "").trim();
|
|
106
|
+
if (!generationId)
|
|
107
|
+
throw new Error("generation_id is required.");
|
|
108
|
+
const result = await hfGet(apiKey, `/generation/${encodeURIComponent(generationId)}`);
|
|
109
|
+
return {
|
|
110
|
+
generation_id: generationId,
|
|
111
|
+
status: result.status ?? null,
|
|
112
|
+
video_url: result.video_url ?? result.url ?? null,
|
|
113
|
+
image_url: result.image_url ?? null,
|
|
114
|
+
created_at: result.created_at ?? null,
|
|
115
|
+
completed_at: result.completed_at ?? null,
|
|
116
|
+
error: result.error ?? null,
|
|
117
|
+
raw: result,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=higgsfield-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"higgsfield-tool.js","sourceRoot":"","sources":["../src/higgsfield-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encrypt a plaintext string using AES-256-GCM.
|
|
3
|
+
* Key is derived from the caller's UnClick API key via PBKDF2.
|
|
4
|
+
*/
|
|
5
|
+
export declare function encrypt(plaintext: string, apiKey: string): {
|
|
6
|
+
encrypted_value: string;
|
|
7
|
+
iv: string;
|
|
8
|
+
auth_tag: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Decrypt a value previously encrypted with encrypt().
|
|
12
|
+
*/
|
|
13
|
+
export declare function decrypt(encrypted_value: string, iv: string, auth_tag: string, apiKey: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the first 12 hex characters of the SHA-256 hash of the API key.
|
|
16
|
+
* Used as a human-readable namespace in logs and error messages.
|
|
17
|
+
*/
|
|
18
|
+
export declare function hashKey(apiKey: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the full SHA-256 hex hash of the API key.
|
|
21
|
+
* Used as the lookup key in Supabase (never store the raw API key).
|
|
22
|
+
*/
|
|
23
|
+
export declare function hashKeyFull(apiKey: string): string;
|
|
24
|
+
//# sourceMappingURL=keychain-crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain-crypto.d.ts","sourceRoot":"","sources":["../src/keychain-crypto.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAU3D;AAED;;GAEG;AACH,wBAAgB,OAAO,CACrB,eAAe,EAAE,MAAM,EACvB,EAAE,EAAe,MAAM,EACvB,QAAQ,EAAS,MAAM,EACvB,MAAM,EAAW,MAAM,GACtB,MAAM,CAQR;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// ─── Keychain Crypto ──────────────────────────────────────────────────────────
|
|
2
|
+
// AES-256-GCM encryption for platform credentials.
|
|
3
|
+
// Key derivation: PBKDF2 with a deterministic salt derived from the API key.
|
|
4
|
+
// No external dependencies - Node.js built-in crypto only.
|
|
5
|
+
import * as crypto from "crypto";
|
|
6
|
+
const PBKDF2_ITERATIONS = 100_000;
|
|
7
|
+
const KEY_BYTES = 32; // AES-256
|
|
8
|
+
const IV_BYTES = 12; // 96-bit IV recommended for GCM
|
|
9
|
+
// Deterministic salt: avoids storing a per-credential salt while still
|
|
10
|
+
// using PBKDF2 for slow key derivation. The secret material is the API key.
|
|
11
|
+
const KEYCHAIN_PEPPER = "unclick-keychain-v1";
|
|
12
|
+
function deriveKey(apiKey) {
|
|
13
|
+
const salt = crypto
|
|
14
|
+
.createHash("sha256")
|
|
15
|
+
.update(`${KEYCHAIN_PEPPER}:${apiKey}`)
|
|
16
|
+
.digest();
|
|
17
|
+
return crypto.pbkdf2Sync(apiKey, salt, PBKDF2_ITERATIONS, KEY_BYTES, "sha256");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Encrypt a plaintext string using AES-256-GCM.
|
|
21
|
+
* Key is derived from the caller's UnClick API key via PBKDF2.
|
|
22
|
+
*/
|
|
23
|
+
export function encrypt(plaintext, apiKey) {
|
|
24
|
+
const key = deriveKey(apiKey);
|
|
25
|
+
const iv = crypto.randomBytes(IV_BYTES);
|
|
26
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
27
|
+
const enc = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
28
|
+
return {
|
|
29
|
+
encrypted_value: enc.toString("hex"),
|
|
30
|
+
iv: iv.toString("hex"),
|
|
31
|
+
auth_tag: cipher.getAuthTag().toString("hex"),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Decrypt a value previously encrypted with encrypt().
|
|
36
|
+
*/
|
|
37
|
+
export function decrypt(encrypted_value, iv, auth_tag, apiKey) {
|
|
38
|
+
const key = deriveKey(apiKey);
|
|
39
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, Buffer.from(iv, "hex"));
|
|
40
|
+
decipher.setAuthTag(Buffer.from(auth_tag, "hex"));
|
|
41
|
+
return Buffer.concat([
|
|
42
|
+
decipher.update(Buffer.from(encrypted_value, "hex")),
|
|
43
|
+
decipher.final(),
|
|
44
|
+
]).toString("utf8");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Returns the first 12 hex characters of the SHA-256 hash of the API key.
|
|
48
|
+
* Used as a human-readable namespace in logs and error messages.
|
|
49
|
+
*/
|
|
50
|
+
export function hashKey(apiKey) {
|
|
51
|
+
return crypto.createHash("sha256").update(apiKey).digest("hex").slice(0, 12);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Returns the full SHA-256 hex hash of the API key.
|
|
55
|
+
* Used as the lookup key in Supabase (never store the raw API key).
|
|
56
|
+
*/
|
|
57
|
+
export function hashKeyFull(apiKey) {
|
|
58
|
+
return crypto.createHash("sha256").update(apiKey).digest("hex");
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=keychain-crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain-crypto.js","sourceRoot":"","sources":["../src/keychain-crypto.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,mDAAmD;AACnD,6EAA6E;AAC7E,2DAA2D;AAE3D,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAClC,MAAM,SAAS,GAAW,EAAE,CAAC,CAAC,UAAU;AACxC,MAAM,QAAQ,GAAY,EAAE,CAAC,CAAC,gCAAgC;AAE9D,uEAAuE;AACvE,4EAA4E;AAC5E,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C,SAAS,SAAS,CAAC,MAAc;IAC/B,MAAM,IAAI,GAAG,MAAM;SAChB,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,GAAG,eAAe,IAAI,MAAM,EAAE,CAAC;SACtC,MAAM,EAAE,CAAC;IACZ,OAAO,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACjF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CACrB,SAAiB,EACjB,MAAc;IAEd,MAAM,GAAG,GAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,EAAE,GAAO,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAM,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACjF,OAAO;QACL,eAAe,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpC,EAAE,EAAe,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;QACnC,QAAQ,EAAS,MAAM,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;KACrD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CACrB,eAAuB,EACvB,EAAuB,EACvB,QAAuB,EACvB,MAAuB;IAEvB,MAAM,GAAG,GAAQ,SAAS,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;IACrF,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;QACpD,QAAQ,CAAC,KAAK,EAAE;KACjB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface SecureInputResult {
|
|
2
|
+
value: string;
|
|
3
|
+
source: "env" | "secure_input" | "direct";
|
|
4
|
+
}
|
|
5
|
+
export declare function checkEnvCredential(platform: string): string | null;
|
|
6
|
+
export declare function startSecureInputServer(platform: string, setupUrl?: string): number;
|
|
7
|
+
export declare function popResolvedCredential(platform: string): string | null;
|
|
8
|
+
export declare function hasActiveServer(platform: string): boolean;
|
|
9
|
+
export interface SecureConnectState {
|
|
10
|
+
status: "found_env" | "found_submitted" | "awaiting_input";
|
|
11
|
+
value?: string;
|
|
12
|
+
source?: "env" | "secure_input";
|
|
13
|
+
url?: string;
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function resolveCredential(platform: string, setupUrl?: string): SecureConnectState;
|
|
17
|
+
//# sourceMappingURL=keychain-secure-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain-secure-input.d.ts","sourceRoot":"","sources":["../src/keychain-secure-input.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,GAAG,cAAc,GAAG,QAAQ,CAAC;CAC3C;AAuED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUlE;AAuDD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA0DlF;AAGD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOrE;AAGD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAID,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAI,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;IAC7D,KAAK,CAAC,EAAI,MAAM,CAAC;IACjB,MAAM,CAAC,EAAG,KAAK,GAAG,cAAc,CAAC;IACjC,GAAG,CAAC,EAAM,MAAM,CAAC;IACjB,OAAO,EAAG,MAAM,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,kBAAkB,CA8BzF"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// ─── UnClick Keychain Secure Input ───────────────────────────────────────────
|
|
2
|
+
// Two-tier credential collection:
|
|
3
|
+
// Tier 1: Check environment variables (common patterns per platform)
|
|
4
|
+
// Tier 2: Spin up a temporary localhost HTTP server with a masked input page
|
|
5
|
+
//
|
|
6
|
+
// IMPORTANT: Credentials never appear in any log, response, or chat message.
|
|
7
|
+
// The localhost server binds to 127.0.0.1 only. Nonce validation prevents replay attacks.
|
|
8
|
+
import { createServer } from "http";
|
|
9
|
+
import { randomBytes } from "crypto";
|
|
10
|
+
// ─── Module-level state ───────────────────────────────────────────────────────
|
|
11
|
+
// These Maps persist across MCP tool calls within the same server process.
|
|
12
|
+
// resolvedCredentials: platform -> credential (submitted by user, ready to pick up)
|
|
13
|
+
// activeServers: platform -> server info (waiting for user to open browser and submit)
|
|
14
|
+
const resolvedCredentials = new Map();
|
|
15
|
+
const activeServers = new Map();
|
|
16
|
+
// ─── Tier 1: Environment variable detection ───────────────────────────────────
|
|
17
|
+
const ENV_MAPPINGS = {
|
|
18
|
+
github: ["GITHUB_TOKEN", "GITHUB_PAT", "GITHUB_API_KEY", "GH_TOKEN"],
|
|
19
|
+
supabase: ["SUPABASE_KEY", "SUPABASE_SERVICE_ROLE_KEY", "SUPABASE_ANON_KEY"],
|
|
20
|
+
vercel: ["VERCEL_TOKEN", "VERCEL_API_TOKEN"],
|
|
21
|
+
stripe: ["STRIPE_SECRET_KEY", "STRIPE_API_KEY", "STRIPE_KEY"],
|
|
22
|
+
openai: ["OPENAI_API_KEY", "OPENAI_KEY"],
|
|
23
|
+
anthropic: ["ANTHROPIC_API_KEY", "ANTHROPIC_KEY"],
|
|
24
|
+
cloudflare: ["CLOUDFLARE_API_TOKEN", "CF_API_TOKEN", "CLOUDFLARE_TOKEN"],
|
|
25
|
+
slack: ["SLACK_BOT_TOKEN", "SLACK_TOKEN", "SLACK_API_TOKEN"],
|
|
26
|
+
discord: ["DISCORD_BOT_TOKEN", "DISCORD_TOKEN"],
|
|
27
|
+
notion: ["NOTION_API_KEY", "NOTION_TOKEN", "NOTION_INTEGRATION_TOKEN"],
|
|
28
|
+
airtable: ["AIRTABLE_API_KEY", "AIRTABLE_PAT"],
|
|
29
|
+
linear: ["LINEAR_API_KEY", "LINEAR_TOKEN"],
|
|
30
|
+
twilio: ["TWILIO_AUTH_TOKEN"],
|
|
31
|
+
sendgrid: ["SENDGRID_API_KEY"],
|
|
32
|
+
mailchimp: ["MAILCHIMP_API_KEY"],
|
|
33
|
+
datadog: ["DD_API_KEY", "DATADOG_API_KEY"],
|
|
34
|
+
pinecone: ["PINECONE_API_KEY"],
|
|
35
|
+
deepl: ["DEEPL_AUTH_KEY", "DEEPL_API_KEY"],
|
|
36
|
+
groq: ["GROQ_API_KEY"],
|
|
37
|
+
mistral: ["MISTRAL_API_KEY"],
|
|
38
|
+
cohere: ["COHERE_API_KEY", "CO_API_KEY"],
|
|
39
|
+
perplexity: ["PERPLEXITY_API_KEY", "PPLX_API_KEY"],
|
|
40
|
+
replicate: ["REPLICATE_API_TOKEN"],
|
|
41
|
+
resend: ["RESEND_API_KEY"],
|
|
42
|
+
postmark: ["POSTMARK_SERVER_TOKEN"],
|
|
43
|
+
sentry: ["SENTRY_AUTH_TOKEN"],
|
|
44
|
+
pagerduty: ["PAGERDUTY_API_KEY"],
|
|
45
|
+
digitalocean: ["DIGITALOCEAN_TOKEN", "DO_API_TOKEN"],
|
|
46
|
+
railway: ["RAILWAY_API_TOKEN"],
|
|
47
|
+
netlify: ["NETLIFY_AUTH_TOKEN"],
|
|
48
|
+
neon: ["NEON_API_KEY"],
|
|
49
|
+
render: ["RENDER_API_KEY"],
|
|
50
|
+
flyio: ["FLY_API_TOKEN"],
|
|
51
|
+
algolia: ["ALGOLIA_API_KEY"],
|
|
52
|
+
mixpanel: ["MIXPANEL_TOKEN"],
|
|
53
|
+
segment: ["SEGMENT_WRITE_KEY"],
|
|
54
|
+
assemblyai: ["ASSEMBLYAI_API_KEY"],
|
|
55
|
+
circleci: ["CIRCLECI_TOKEN"],
|
|
56
|
+
shopify: ["SHOPIFY_ACCESS_TOKEN"],
|
|
57
|
+
upstash: ["UPSTASH_REDIS_REST_TOKEN"],
|
|
58
|
+
turso: ["TURSO_AUTH_TOKEN"],
|
|
59
|
+
convertkit: ["CONVERTKIT_API_KEY"],
|
|
60
|
+
gumroad: ["GUMROAD_ACCESS_TOKEN"],
|
|
61
|
+
lemonsqueezy: ["LEMONSQUEEZY_API_KEY"],
|
|
62
|
+
togetherai: ["TOGETHER_API_KEY"],
|
|
63
|
+
higgsfield: ["HIGGSFIELD_API_KEY"],
|
|
64
|
+
heygen: ["HEYGEN_API_KEY"],
|
|
65
|
+
runway: ["RUNWAY_API_KEY"],
|
|
66
|
+
pika: ["PIKA_API_KEY"],
|
|
67
|
+
kling: ["KLING_API_KEY"],
|
|
68
|
+
};
|
|
69
|
+
export function checkEnvCredential(platform) {
|
|
70
|
+
const vars = ENV_MAPPINGS[platform] ?? [
|
|
71
|
+
`${platform.toUpperCase()}_API_KEY`,
|
|
72
|
+
`${platform.toUpperCase()}_TOKEN`,
|
|
73
|
+
];
|
|
74
|
+
for (const v of vars) {
|
|
75
|
+
const val = process.env[v];
|
|
76
|
+
if (val && val.length > 5)
|
|
77
|
+
return val;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
// ─── Tier 2: Temporary localhost secure input page ────────────────────────────
|
|
82
|
+
function buildHtml(platform, nonce, setupUrl) {
|
|
83
|
+
const setupLink = setupUrl
|
|
84
|
+
? ` <a href="${setupUrl}" target="_blank">Get your key here</a>.`
|
|
85
|
+
: "";
|
|
86
|
+
return `<!DOCTYPE html>
|
|
87
|
+
<html><head>
|
|
88
|
+
<title>UnClick BackstagePass - Connect ${platform}</title>
|
|
89
|
+
<meta charset="utf-8">
|
|
90
|
+
<style>
|
|
91
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
92
|
+
body { background: #0a0a0a; color: #e0e0e0; font-family: -apple-system, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; }
|
|
93
|
+
.card { background: #1a1a1a; border: 1px solid #333; border-radius: 12px; padding: 40px; max-width: 480px; width: 100%; }
|
|
94
|
+
h1 { font-size: 20px; margin-bottom: 8px; color: #61c1c4; }
|
|
95
|
+
p { font-size: 14px; color: #888; margin-bottom: 24px; }
|
|
96
|
+
a { color: #61c1c4; }
|
|
97
|
+
label { font-size: 13px; color: #aaa; display: block; margin-bottom: 8px; }
|
|
98
|
+
input[type="password"] { width: 100%; padding: 12px; background: #111; border: 1px solid #333; border-radius: 8px; color: #fff; font-size: 14px; font-family: monospace; }
|
|
99
|
+
input:focus { outline: none; border-color: #61c1c4; }
|
|
100
|
+
button { width: 100%; padding: 12px; background: #61c1c4; color: #0a0a0a; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; margin-top: 16px; }
|
|
101
|
+
button:hover { background: #4fa8ab; }
|
|
102
|
+
.note { font-size: 12px; color: #555; margin-top: 16px; text-align: center; }
|
|
103
|
+
.success { text-align: center; }
|
|
104
|
+
.success h1 { font-size: 24px; margin-bottom: 16px; }
|
|
105
|
+
</style>
|
|
106
|
+
</head><body>
|
|
107
|
+
<div class="card" id="form">
|
|
108
|
+
<h1>Connect ${platform}</h1>
|
|
109
|
+
<p>Paste your API key below. It will be encrypted and stored securely. This page closes automatically after submission.${setupLink}</p>
|
|
110
|
+
<label>API Key</label>
|
|
111
|
+
<input type="password" id="key" placeholder="Paste your key here" autofocus>
|
|
112
|
+
<button onclick="submit()">Connect</button>
|
|
113
|
+
<div class="note">Your key goes directly to local encryption. It never appears in your AI chat.</div>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="card success" id="done" style="display:none">
|
|
116
|
+
<h1>Connected</h1>
|
|
117
|
+
<p>Your ${platform} key has been encrypted and stored. You can close this tab.</p>
|
|
118
|
+
</div>
|
|
119
|
+
<script>
|
|
120
|
+
async function submit() {
|
|
121
|
+
const key = document.getElementById('key').value.trim();
|
|
122
|
+
if (!key) return;
|
|
123
|
+
const res = await fetch('/submit', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({key, nonce:'${nonce}'}) });
|
|
124
|
+
if (res.ok) { document.getElementById('form').style.display='none'; document.getElementById('done').style.display='block'; setTimeout(() => window.close(), 2000); }
|
|
125
|
+
}
|
|
126
|
+
document.getElementById('key').addEventListener('keydown', e => { if (e.key === 'Enter') submit(); });
|
|
127
|
+
</script>
|
|
128
|
+
</body></html>`;
|
|
129
|
+
}
|
|
130
|
+
// Start a localhost server for the given platform. Stores result in resolvedCredentials when submitted.
|
|
131
|
+
// Returns port number immediately (non-blocking).
|
|
132
|
+
export function startSecureInputServer(platform, setupUrl) {
|
|
133
|
+
// If a server for this platform is already running, reuse it
|
|
134
|
+
const existing = activeServers.get(platform);
|
|
135
|
+
if (existing)
|
|
136
|
+
return existing.port;
|
|
137
|
+
const nonce = randomBytes(8).toString("hex");
|
|
138
|
+
// Use a deterministic-ish port range: 19283-19382
|
|
139
|
+
const port = 19283 + Math.floor(Math.random() * 100);
|
|
140
|
+
const html = buildHtml(platform, nonce, setupUrl);
|
|
141
|
+
const server = createServer((req, res) => {
|
|
142
|
+
if (req.method === "GET") {
|
|
143
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
144
|
+
res.end(html);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (req.method === "POST" && req.url === "/submit") {
|
|
148
|
+
let body = "";
|
|
149
|
+
req.on("data", (chunk) => { body += chunk; });
|
|
150
|
+
req.on("end", () => {
|
|
151
|
+
try {
|
|
152
|
+
const data = JSON.parse(body);
|
|
153
|
+
if (data.nonce === nonce && data.key && data.key.length > 5) {
|
|
154
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
155
|
+
res.end('{"ok":true}');
|
|
156
|
+
// Store resolved credential and clean up
|
|
157
|
+
resolvedCredentials.set(platform, data.key);
|
|
158
|
+
activeServers.delete(platform);
|
|
159
|
+
setTimeout(() => server.close(), 3000);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
res.writeHead(400);
|
|
163
|
+
res.end("Invalid");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
res.writeHead(400);
|
|
168
|
+
res.end("Bad request");
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
res.writeHead(404);
|
|
174
|
+
res.end("Not found");
|
|
175
|
+
});
|
|
176
|
+
server.listen(port, "127.0.0.1");
|
|
177
|
+
activeServers.set(platform, { port, server, nonce });
|
|
178
|
+
// Auto-shutdown after 5 minutes
|
|
179
|
+
setTimeout(() => {
|
|
180
|
+
if (activeServers.has(platform)) {
|
|
181
|
+
activeServers.delete(platform);
|
|
182
|
+
server.close();
|
|
183
|
+
}
|
|
184
|
+
}, 300_000);
|
|
185
|
+
return port;
|
|
186
|
+
}
|
|
187
|
+
// Check if a submitted credential is waiting to be picked up
|
|
188
|
+
export function popResolvedCredential(platform) {
|
|
189
|
+
const val = resolvedCredentials.get(platform);
|
|
190
|
+
if (val !== undefined) {
|
|
191
|
+
resolvedCredentials.delete(platform);
|
|
192
|
+
return val;
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
// Check if an input server is currently active for a platform
|
|
197
|
+
export function hasActiveServer(platform) {
|
|
198
|
+
return activeServers.has(platform);
|
|
199
|
+
}
|
|
200
|
+
export function resolveCredential(platform, setupUrl) {
|
|
201
|
+
// Tier 1: environment
|
|
202
|
+
const envVal = checkEnvCredential(platform);
|
|
203
|
+
if (envVal) {
|
|
204
|
+
return {
|
|
205
|
+
status: "found_env",
|
|
206
|
+
value: envVal,
|
|
207
|
+
source: "env",
|
|
208
|
+
message: `Credential for ${platform} found in environment.`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
// Check if user already submitted via browser
|
|
212
|
+
const submitted = popResolvedCredential(platform);
|
|
213
|
+
if (submitted) {
|
|
214
|
+
return {
|
|
215
|
+
status: "found_submitted",
|
|
216
|
+
value: submitted,
|
|
217
|
+
source: "secure_input",
|
|
218
|
+
message: `Credential for ${platform} received via secure input page.`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
// Tier 2: start (or reuse) the localhost server
|
|
222
|
+
const port = startSecureInputServer(platform, setupUrl);
|
|
223
|
+
return {
|
|
224
|
+
status: "awaiting_input",
|
|
225
|
+
url: `http://localhost:${port}`,
|
|
226
|
+
message: `Open http://localhost:${port} to securely enter your ${platform} API key. Then call keychain_secure_connect again to complete the connection.`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=keychain-secure-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain-secure-input.js","sourceRoot":"","sources":["../src/keychain-secure-input.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,kCAAkC;AAClC,uEAAuE;AACvE,+EAA+E;AAC/E,EAAE;AACF,6EAA6E;AAC7E,0FAA0F;AAE1F,OAAO,EAAE,YAAY,EAAe,MAAM,MAAM,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAerC,iFAAiF;AACjF,2EAA2E;AAC3E,oFAAoF;AACpF,uFAAuF;AAEvF,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAC;AACtD,MAAM,aAAa,GAAS,IAAI,GAAG,EAAwB,CAAC;AAE5D,iFAAiF;AAEjF,MAAM,YAAY,GAA6B;IAC7C,MAAM,EAAQ,CAAC,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,CAAC;IAC1E,QAAQ,EAAM,CAAC,cAAc,EAAE,2BAA2B,EAAE,mBAAmB,CAAC;IAChF,MAAM,EAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAClD,MAAM,EAAQ,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,YAAY,CAAC;IACnE,MAAM,EAAQ,CAAC,gBAAgB,EAAE,YAAY,CAAC;IAC9C,SAAS,EAAK,CAAC,mBAAmB,EAAE,eAAe,CAAC;IACpD,UAAU,EAAI,CAAC,sBAAsB,EAAE,cAAc,EAAE,kBAAkB,CAAC;IAC1E,KAAK,EAAS,CAAC,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,CAAC;IACnE,OAAO,EAAO,CAAC,mBAAmB,EAAE,eAAe,CAAC;IACpD,MAAM,EAAQ,CAAC,gBAAgB,EAAE,cAAc,EAAE,0BAA0B,CAAC;IAC5E,QAAQ,EAAM,CAAC,kBAAkB,EAAE,cAAc,CAAC;IAClD,MAAM,EAAQ,CAAC,gBAAgB,EAAE,cAAc,CAAC;IAChD,MAAM,EAAQ,CAAC,mBAAmB,CAAC;IACnC,QAAQ,EAAM,CAAC,kBAAkB,CAAC;IAClC,SAAS,EAAK,CAAC,mBAAmB,CAAC;IACnC,OAAO,EAAO,CAAC,YAAY,EAAE,iBAAiB,CAAC;IAC/C,QAAQ,EAAM,CAAC,kBAAkB,CAAC;IAClC,KAAK,EAAS,CAAC,gBAAgB,EAAE,eAAe,CAAC;IACjD,IAAI,EAAU,CAAC,cAAc,CAAC;IAC9B,OAAO,EAAO,CAAC,iBAAiB,CAAC;IACjC,MAAM,EAAQ,CAAC,gBAAgB,EAAE,YAAY,CAAC;IAC9C,UAAU,EAAI,CAAC,oBAAoB,EAAE,cAAc,CAAC;IACpD,SAAS,EAAK,CAAC,qBAAqB,CAAC;IACrC,MAAM,EAAQ,CAAC,gBAAgB,CAAC;IAChC,QAAQ,EAAM,CAAC,uBAAuB,CAAC;IACvC,MAAM,EAAQ,CAAC,mBAAmB,CAAC;IACnC,SAAS,EAAK,CAAC,mBAAmB,CAAC;IACnC,YAAY,EAAE,CAAC,oBAAoB,EAAE,cAAc,CAAC;IACpD,OAAO,EAAO,CAAC,mBAAmB,CAAC;IACnC,OAAO,EAAO,CAAC,oBAAoB,CAAC;IACpC,IAAI,EAAU,CAAC,cAAc,CAAC;IAC9B,MAAM,EAAQ,CAAC,gBAAgB,CAAC;IAChC,KAAK,EAAS,CAAC,eAAe,CAAC;IAC/B,OAAO,EAAO,CAAC,iBAAiB,CAAC;IACjC,QAAQ,EAAM,CAAC,gBAAgB,CAAC;IAChC,OAAO,EAAO,CAAC,mBAAmB,CAAC;IACnC,UAAU,EAAI,CAAC,oBAAoB,CAAC;IACpC,QAAQ,EAAM,CAAC,gBAAgB,CAAC;IAChC,OAAO,EAAO,CAAC,sBAAsB,CAAC;IACtC,OAAO,EAAO,CAAC,0BAA0B,CAAC;IAC1C,KAAK,EAAS,CAAC,kBAAkB,CAAC;IAClC,UAAU,EAAI,CAAC,oBAAoB,CAAC;IACpC,OAAO,EAAO,CAAC,sBAAsB,CAAC;IACtC,YAAY,EAAE,CAAC,sBAAsB,CAAC;IACtC,UAAU,EAAI,CAAC,kBAAkB,CAAC;IAClC,UAAU,EAAI,CAAC,oBAAoB,CAAC;IACpC,MAAM,EAAQ,CAAC,gBAAgB,CAAC;IAChC,MAAM,EAAQ,CAAC,gBAAgB,CAAC;IAChC,IAAI,EAAU,CAAC,cAAc,CAAC;IAC9B,KAAK,EAAS,CAAC,eAAe,CAAC;CAChC,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI;QACrC,GAAG,QAAQ,CAAC,WAAW,EAAE,UAAU;QACnC,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ;KAClC,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iFAAiF;AAEjF,SAAS,SAAS,CAAC,QAAgB,EAAE,KAAa,EAAE,QAAiB;IACnE,MAAM,SAAS,GAAG,QAAQ;QACxB,CAAC,CAAC,aAAa,QAAQ,0CAA0C;QACjE,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;;yCAEgC,QAAQ;;;;;;;;;;;;;;;;;;;;gBAoBjC,QAAQ;2HACmG,SAAS;;;;;;;;YAQxH,QAAQ;;;;;;yIAMqH,KAAK;;;;;eAK/H,CAAC;AAChB,CAAC;AAED,wGAAwG;AACxG,kDAAkD;AAClD,MAAM,UAAU,sBAAsB,CAAC,QAAgB,EAAE,QAAiB;IACxE,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;IAEnC,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC7C,kDAAkD;IAClD,MAAM,IAAI,GAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IACtD,MAAM,IAAI,GAAI,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAEnD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACzB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YACnD,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAqC,CAAC;oBAClE,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC5D,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;wBAC3D,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;wBACvB,yCAAyC;wBACzC,mBAAmB,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;wBAC5C,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;wBAC/B,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;oBACzC,CAAC;yBAAM,CAAC;wBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;wBACnB,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;oBACrB,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACjC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAErD,gCAAgC;IAChC,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;IACH,CAAC,EAAE,OAAO,CAAC,CAAC;IAEZ,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,MAAM,GAAG,GAAG,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AAYD,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,QAAiB;IACnE,sBAAsB;IACtB,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO;YACL,MAAM,EAAG,WAAW;YACpB,KAAK,EAAI,MAAM;YACf,MAAM,EAAG,KAAK;YACd,OAAO,EAAE,kBAAkB,QAAQ,wBAAwB;SAC5D,CAAC;IACJ,CAAC;IAED,8CAA8C;IAC9C,MAAM,SAAS,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAClD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO;YACL,MAAM,EAAG,iBAAiB;YAC1B,KAAK,EAAI,SAAS;YAClB,MAAM,EAAG,cAAc;YACvB,OAAO,EAAE,kBAAkB,QAAQ,kCAAkC;SACtE,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,MAAM,IAAI,GAAG,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACxD,OAAO;QACL,MAAM,EAAG,gBAAgB;QACzB,GAAG,EAAM,oBAAoB,IAAI,EAAE;QACnC,OAAO,EAAE,yBAAyB,IAAI,2BAA2B,QAAQ,+EAA+E;KACzJ,CAAC;AACJ,CAAC"}
|