Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
"hooks": {
"pre-commit": "npm run lint"
}
}
},
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
export function setOptions(options: StoredOptions) {
userale.options({ url: options.loggingUrl })
allowListRegExp = new RegExp(options.allowList)

switch (options.authMode) {
case "oauth":
userale.options({
authHeader: options.accessToken ? `Bearer ${options.accessToken}` : null,
apiKey: null
})
break
case "apikey":
userale.options({
authHeader: null,
apiKey: options.apiKey || null
})
break
default:
userale.options({ authHeader: null, apiKey: null })
}
}

export function getAllowListRegExp() {
Expand Down
140 changes: 117 additions & 23 deletions products/userale/packages/flagon-userale-ext/src/options/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,47 @@
*/

import pkceChallenge from "pkce-challenge"
import { useState } from "react"
import { useEffect, useState } from "react"
import browser from "webextension-polyfill"

import { setStoredOptions } from "~/utils/storage"
import { getStoredOptions, setStoredOptions } from "~/utils/storage"
import type { StoredOptions } from "~/utils/storage"

function Auth() {
const [authMode, setAuthMode] = useState<StoredOptions["authMode"]>("none")
const [apiKey, setApiKey] = useState("")
const [issuerUrl, setIssuerUrl] = useState("")
const [clientId, setClientId] = useState("")
const [message, setMessage] = useState("")

useEffect(() => {
getStoredOptions().then((opts) => {
setAuthMode(opts.authMode)
setApiKey(opts.apiKey)
})
}, [])

const handleAuthModeChange = async (
mode: StoredOptions["authMode"]
) => {
setAuthMode(mode)
setMessage("")
if (mode === "none") {
await setStoredOptions({ authMode: "none", accessToken: "", apiKey: "" })
setApiKey("")
setMessage("Auth disabled.")
}
}

const handleSaveApiKey = async () => {
await setStoredOptions({
authMode: "apikey",
apiKey,
accessToken: ""
})
setMessage("API key saved.")
}

const handleLogin = async () => {
try {
// Generate the PKCE challenge pair (code_verifier and code_challenge)
Expand Down Expand Up @@ -74,7 +105,11 @@ function Auth() {
)

const tokens = await tokenRes.json()
await setStoredOptions({ accessToken: tokens.access_token })
await setStoredOptions({
authMode: "oauth",
accessToken: tokens.access_token,
apiKey: ""
})

setMessage("Login successful!")
} catch (err) {
Expand All @@ -85,32 +120,91 @@ function Auth() {

return (
<div>
<h2>OAuth Login</h2>
<form onSubmit={handleLogin}>
<div>
<label>Issuer URL:</label>
<h2>Authentication</h2>
<div>
<label>
<input
type="url"
value={issuerUrl}
onChange={(e) => setIssuerUrl(e.target.value)}
placeholder="https://issuer.com/realms/myrealm"
required
type="radio"
name="authMode"
value="none"
checked={authMode === "none"}
onChange={() => handleAuthModeChange("none")}
/>
</div>
<div>
<label>Client ID:</label>
None
</label>
<label style={{ marginLeft: 16 }}>
<input
type="radio"
name="authMode"
value="oauth"
checked={authMode === "oauth"}
onChange={() => handleAuthModeChange("oauth")}
/>
OAuth
</label>
<label style={{ marginLeft: 16 }}>
<input
type="text"
value={clientId}
onChange={(e) => setClientId(e.target.value)}
placeholder="your-client-id"
required
type="radio"
name="authMode"
value="apikey"
checked={authMode === "apikey"}
onChange={() => handleAuthModeChange("apikey")}
/>
API Key
</label>
</div>

{authMode === "oauth" && (
<div>
<h3>OAuth Login</h3>
<form onSubmit={handleLogin}>
<div>
<label>Issuer URL:</label>
<input
type="url"
value={issuerUrl}
onChange={(e) => setIssuerUrl(e.target.value)}
placeholder="https://issuer.com/realms/myrealm"
required
/>
</div>
<div>
<label>Client ID:</label>
<input
type="text"
value={clientId}
onChange={(e) => setClientId(e.target.value)}
placeholder="your-client-id"
required
/>
</div>
<div style={{ textAlign: "right" }}>
<button type="submit">Log In</button>
</div>
</form>
</div>
<div style={{ textAlign: "right" }}>
<button type="submit">Log In</button>
)}

{authMode === "apikey" && (
<div>
<h3>API Key</h3>
<div>
<label>API Key:</label>
<input
type="password"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
placeholder="Enter your API key"
/>
</div>
<div style={{ textAlign: "right" }}>
<button type="button" onClick={handleSaveApiKey}>
Save
</button>
</div>
</div>
</form>
)}

{message && <p>{message}</p>}
</div>
)
Expand Down
12 changes: 10 additions & 2 deletions products/userale/packages/flagon-userale-ext/src/utils/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { sendToBackground } from "@plasmohq/messaging"

export const STORAGE_KEYS = {
accessToken: "accessToken",
apiKey: "apiKey",
authMode: "authMode",
allowList: "allowList",
loggingUrl: "loggingUrl"
} as const
Expand All @@ -31,12 +33,16 @@ export type StorageKeys = keyof typeof STORAGE_KEYS

export type StoredOptions = {
accessToken: string
apiKey: string
authMode: "oauth" | "apikey" | "none"
allowList: string
loggingUrl: string
}

const DEFAULT_OPTIONS: StoredOptions = {
accessToken: "",
apiKey: "",
authMode: "none",
allowList: "https://flagon.apache.org/",
loggingUrl: "http://localhost:8000"
}
Expand All @@ -48,6 +54,8 @@ export async function getStoredOptions(): Promise<StoredOptions> {

return {
accessToken: stored.accessToken ?? DEFAULT_OPTIONS.accessToken,
apiKey: stored.apiKey ?? DEFAULT_OPTIONS.apiKey,
authMode: stored.authMode ?? DEFAULT_OPTIONS.authMode,
allowList: stored.allowList ?? DEFAULT_OPTIONS.allowList,
loggingUrl: stored.loggingUrl ?? DEFAULT_OPTIONS.loggingUrl
}
Expand All @@ -57,8 +65,8 @@ export async function getStoredOptions(): Promise<StoredOptions> {
export async function setStoredOptions(values: Partial<StoredOptions>) {
// Validate the new options
try {
new RegExp(values.allowList)
new URL(values.loggingUrl)
if (values.allowList !== undefined) new RegExp(values.allowList)
if (values.loggingUrl !== undefined) new URL(values.loggingUrl)
} catch (error) {
return error
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type { Settings } from "@/types";
export declare class Configuration {
[key: string]: Settings.ConfigValueTypes;
private static instance;
apiKey: Settings.ApiKey;
autostart: boolean;
authHeader: Settings.AuthHeader;
browserSessionId: Settings.SessionId;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions products/userale/packages/flagon-userale/build/main.global.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions products/userale/packages/flagon-userale/build/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ var httpSessionId = null;
function getInitialSettings() {
if (typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope) {
const settings2 = {
apiKey: null,
authHeader: null,
autostart: true,
browserSessionId: null,
Expand Down Expand Up @@ -577,6 +578,7 @@ function getInitialSettings() {
};
const headers = get("data-headers");
const settings = {
apiKey: get("data-api-key") || null,
authHeader: get("data-auth") || null,
autostart: get("data-autostart") === "false" ? false : true,
browserSessionId: null,
Expand Down Expand Up @@ -642,6 +644,7 @@ function generatehttpSessionId() {
// src/configure.ts
var _Configuration = class {
constructor() {
this.apiKey = null;
this.autostart = false;
this.authHeader = null;
this.browserSessionId = null;
Expand Down Expand Up @@ -754,6 +757,9 @@ function sendOnClose(logs3, config3) {
if (config3.authHeader) {
headers.set("Authorization", config3.authHeader.toString());
}
if (config3.apiKey) {
headers.set("x-api-key", config3.apiKey);
}
fetch(config3.url, {
keepalive: true,
method: "POST",
Expand Down Expand Up @@ -782,6 +788,9 @@ async function sendLogs(logs3, config3, retries) {
const authHeaderValue = typeof config3.authHeader === "function" ? config3.authHeader() : config3.authHeader;
headers.set("Authorization", authHeaderValue);
}
if (config3.apiKey) {
headers.set("x-api-key", config3.apiKey);
}
updateCustomHeaders(config3);
if (config3.headers) {
for (const [header, value] of Object.entries(config3.headers)) {
Expand Down

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions products/userale/packages/flagon-userale/src/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class Configuration {
private static instance: Configuration | null = null;

// Public properties corresponding to fields in the Config interface
public apiKey: Settings.ApiKey = null;
public autostart: boolean = false;
public authHeader: Settings.AuthHeader = null;
public browserSessionId: Settings.SessionId = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function getInitialSettings(): Settings.Config {
self instanceof WorkerGlobalScope
) {
const settings: Settings.Config = {
apiKey: null,
authHeader: null,
autostart: true,
browserSessionId: null,
Expand Down Expand Up @@ -81,6 +82,7 @@ export function getInitialSettings(): Settings.Config {
};
const headers = get("data-headers");
const settings: Settings.Config = {
apiKey: get("data-api-key") || null,
authHeader: get("data-auth") || null,
autostart: get("data-autostart") === "false" ? false : true,
browserSessionId: null,
Expand Down
Loading
Loading