Skip to content

Commit

Permalink
Move authorization code to a file
Browse files Browse the repository at this point in the history
  • Loading branch information
jessitron committed Jan 27, 2025
1 parent c6b2b1b commit 77e4651
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 158 deletions.
157 changes: 0 additions & 157 deletions src/ApiKeyPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import { Html, html } from "./htm-but-right";
import { trace } from "@opentelemetry/api";
import {
Region,
KeyType,
KeyInfo,
EnvironmentType,
HoneycombAuthResponse,
HoneycombApiEndpointByRegion,
describeAuthorization,
HnyTricksAuthorization,
} from "./common";
import { fetchFromHoneycombApi, isFetchError } from "./HoneycombApi";
import {
currentTraceId,
inSpan,
inSpanAsync,
recordError,
report,
Expand Down Expand Up @@ -55,126 +49,6 @@ export function ApiKeyPrompt(params: {
</section>`;
}

export function commentOnApiKey(apiKey: string): Html {
if (!apiKey) {
return "";
}
const keyInfo = interpretApiKey(apiKey);
const remark = remarkOnKeyInfo(keyInfo);

return html`<span
class="${remark.className}"
data-traceid="${currentTraceId()}"
>${remark.description}</span
>`;
}

function remarkOnKeyInfo(keyInfo): {
className: "happy" | "unhappy";
description: string;
} {
if (keyInfo.type === "ingest") {
if (keyInfo.region !== "unknown") {
return {
className: "happy",
description: `This looks like a ${keyInfo.region} ingest key`,
};
} else {
return {
className: "unhappy",
description:
"This looks like an ingest key, but I can't tell which region",
};
}
} else if (
keyInfo.type === "configuration" &&
keyInfo.environmentType === "classic"
) {
return {
className: "happy",
description: "That looks like a Honeycomb Classic configuration key.",
};
} else if (keyInfo.type === "configuration") {
return {
className: "happy",
description: "That looks like a Honeycomb configuration key. Great.",
};
} else if (keyInfo.type === "management key ID") {
return {
className: "unhappy",
description:
"That looks like a management key ID. I need a configuration or ingest key.",
};
} else if (keyInfo.type === "management key secret") {
return {
className: "unhappy",
description:
"That might be a management key secret. I need a configuration or ingest key.",
};
}
return {
className: "unhappy",
description: "That doesn't look like an API key",
};
}

export function regionByLetter(letter: string): Region {
switch (letter) {
case "a":
return "US";
case "b":
return "EU";
case "c":
return "dogfood US";
case "d":
return "dogfood EU";
case "e":
return "kibble US";
case "f":
return "kibble EU";
}
}

export function interpretApiKey(apiKey: string): KeyInfo {
let keyType: KeyType = "none";
let region: Region = "unknown";
let environmentType: EnvironmentType = "none";
if (apiKey.length === 64 && apiKey.match(/^hc[abcdef]i[kc]_[a-z0-9]{58}$/)) {
keyType = "ingest";
region = regionByLetter(apiKey[2]);
switch (apiKey[4]) {
case "c":
environmentType = "classic";
break;
case "k":
environmentType = "e&s";
break;
}
} else if (apiKey.match(/^[a-zA-Z0-9]{22}$/)) {
keyType = "configuration";
environmentType = "e&s";
region = "unknowable";
} else if (apiKey.match(/^[a-f0-9]{32}$/)) {
keyType = "configuration";
environmentType = "classic";
region = "unknowable";
} else if (apiKey.match(/^hc[abcdef]mk_[a-z0-9]{26}$/)) {
keyType = "management key ID";
environmentType = "none";
region = regionByLetter(apiKey[2]);
} else if (apiKey.match(/^[a-z0-9]{32}$/)) {
keyType = "management key secret";
environmentType = "none";
region = "unknowable";
}
trace.getActiveSpan()?.setAttributes({
"honeycomb.key.type": keyType,
"honeycomb.key.region": region,
"honeycomb.key.environmentType": environmentType,
});
return { type: keyType, environmentType, region };
}

export type AuthError = {
authError: true;
html: Html;
Expand Down Expand Up @@ -205,37 +79,6 @@ export async function authorize(
</div>`
);
}

const keyInfo = interpretApiKey(apiKey);
if (keyInfo.region === "unknown") {
return authError(html`<div>
<span class="unhappy">This doesn't look like an API key</span>
</div>`);
}
if (keyInfo.region === "unknowable") {
const workingRegion = await tryAllRegions(apiKey);
if (workingRegion === "unknown") {
return authError(html`<div>
<span class="unhappy">
That API key did not work in any Honeycomb region. 😭
</span>
</div>`);
}
keyInfo.region = workingRegion; // now we know.
}
const response = await fetchFromHoneycombApi<HoneycombAuthResponse>(
{ apiKey, keyInfo },
"auth"
);
trace
.getActiveSpan()
?.setAttributes({ "honeycomb.auth.response": JSON.stringify(response) });
if (isFetchError(response)) {
return authError(html`<div>
<span class="unhappy">Auth check failed: ${response.message}</span>
</div>`);
}
return describeAuthorization(apiKey, keyInfo, response);
}

async function tryAllRegions(apiKey: string): Promise<Region> {
Expand Down
123 changes: 123 additions & 0 deletions src/auth/validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { EnvironmentType, KeyInfo, KeyType, Region } from "../common";
import { Html, html } from "../htm-but-right";
import { currentTraceId, report } from "../tracing-util";

export function commentOnApiKey(apiKey: string): Html {
if (!apiKey) {
return "";
}
const keyInfo = interpretApiKey(apiKey);
const remark = remarkOnKeyInfo(keyInfo);

return html`<span
class="${remark.className}"
data-traceid="${currentTraceId()}"
>${remark.description}</span
>`;
}

function remarkOnKeyInfo(keyInfo): {
className: "happy" | "unhappy";
description: string;
} {
if (keyInfo.type === "ingest") {
if (keyInfo.region !== "unknown") {
return {
className: "happy",
description: `This looks like a ${keyInfo.region} ingest key`,
};
} else {
return {
className: "unhappy",
description:
"This looks like an ingest key, but I can't tell which region",
};
}
} else if (
keyInfo.type === "configuration" &&
keyInfo.environmentType === "classic"
) {
return {
className: "happy",
description: "That looks like a Honeycomb Classic configuration key.",
};
} else if (keyInfo.type === "configuration") {
return {
className: "happy",
description: "That looks like a Honeycomb configuration key. Great.",
};
} else if (keyInfo.type === "management key ID") {
return {
className: "unhappy",
description:
"That looks like a management key ID. I need a configuration or ingest key.",
};
} else if (keyInfo.type === "management key secret") {
return {
className: "unhappy",
description:
"That might be a management key secret. I need a configuration or ingest key.",
};
}
return {
className: "unhappy",
description: "That doesn't look like an API key",
};
}

function regionByLetter(letter: string): Region {
switch (letter) {
case "a":
return "US";
case "b":
return "EU";
case "c":
return "dogfood US";
case "d":
return "dogfood EU";
case "e":
return "kibble US";
case "f":
return "kibble EU";
}
}

export function interpretApiKey(apiKey: string): KeyInfo {
let keyType: KeyType = "none";
let region: Region = "unknown";
let environmentType: EnvironmentType = "none";
if (apiKey.length === 64 && apiKey.match(/^hc[abcdef]i[kc]_[a-z0-9]{58}$/)) {
keyType = "ingest";
region = regionByLetter(apiKey[2]);
switch (apiKey[4]) {
case "c":
environmentType = "classic";
break;
case "k":
environmentType = "e&s";
break;
}
} else if (apiKey.match(/^[a-zA-Z0-9]{22}$/)) {
keyType = "configuration";
environmentType = "e&s";
region = "unknowable";
} else if (apiKey.match(/^[a-f0-9]{32}$/)) {
keyType = "configuration";
environmentType = "classic";
region = "unknowable";
} else if (apiKey.match(/^hc[abcdef]mk_[a-z0-9]{26}$/)) {
keyType = "management key ID";
environmentType = "none";
region = regionByLetter(apiKey[2]);
} else if (apiKey.match(/^[a-z0-9]{32}$/)) {
keyType = "management key secret";
environmentType = "none";
region = "unknowable";
}
report({
"honeycomb.key.type": keyType,
"honeycomb.key.region": region,
"honeycomb.key.environmentType": environmentType,
});
return { type: keyType, environmentType, region };
}
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
} from "./event/AuthError";

import { fakeAuthEndpoint } from "./FakeRegion";
import { commentOnApiKey } from "./ApiKeyPrompt";
import { parseAuthData, team } from "./Team";
import { index } from "./index";
import { traceActions } from "./TraceSection";
Expand All @@ -23,6 +22,7 @@ import { describeDatasets } from "./datasets/datasets";
import { sendEventSection } from "./event/SendEvent";
import { statusDiv } from "./status";
import { sendEvent } from "./event/send";
import { commentOnApiKey } from "./auth/validate";

const app = express();
const port = process.env.PORT || 3000;
Expand Down

0 comments on commit 77e4651

Please sign in to comment.