web: isolate clipboard handling (#7229)

We would like to use the clipboard for more than just the token copy button.  This commit
enables that by separating the "Write to Clipboard" and "Write to Notifications" routines
into separate functions, putting "writeToClipboard" into the utilities collection, and
clarifying what happens when a custom presses the TokenCopy button.
This commit is contained in:
Ken Sternberg 2023-10-19 16:26:02 -07:00 committed by GitHub
parent 92d170d065
commit 7e536515c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 26 deletions

View File

@ -1,12 +1,14 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { MessageLevel } from "@goauthentik/common/messages"; import { MessageLevel } from "@goauthentik/common/messages";
import { showMessage } from "@goauthentik/elements/messages/MessageContainer"; import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
import { isSafari } from "@goauthentik/elements/utils/isSafari"; import { writeToClipboard } from "@goauthentik/elements/utils/writeToClipboard";
import { msg } from "@lit/localize";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { CoreApi, ResponseError, TokenView } from "@goauthentik/api"; import { CoreApi, ResponseError, TokenView } from "@goauthentik/api";
import { APIMessage } from "../../messages/Message";
import BaseTaskButton from "../SpinnerButton/BaseTaskButton"; import BaseTaskButton from "../SpinnerButton/BaseTaskButton";
/** /**
@ -51,35 +53,26 @@ export class TokenCopyButton extends BaseTaskButton {
}); });
}; };
onSuccess(token: unknown) { async onSuccess(token: unknown) {
super.onSuccess(token); super.onSuccess(token);
if (!isTokenView(token)) { if (!isTokenView(token)) {
throw new Error(`Unrecognized return from server: ${token}`); throw new Error(`Unrecognized return from server: ${token}`);
} }
const wroteToClipboard = await writeToClipboard(token.key as string);
// Insecure origins may not have access to the clipboard. Show a message instead. const info: Pick<APIMessage, "message" | "description"> = wroteToClipboard
if (!navigator.clipboard) { ? {
showMessage({ message: msg("The token has been copied to your clipboard"),
level: MessageLevel.info, }
message: token.key as string, : {
}); message: token.key,
return; description: msg(
} "The token was displayed because authentik does not have permission to write to the clipboard",
),
// Safari only allows navigator.clipboard.write with native clipboard items. };
if (isSafari()) { showMessage({
navigator.clipboard.write([ level: MessageLevel.info,
new ClipboardItem({ ...info,
"text/plain": new Blob([token.key as string], { });
type: "text/plain",
}),
}),
]);
return;
}
// Default behavior: write the token to the clipboard.
navigator.clipboard.writeText(token.key as string);
} }
async onError(error: unknown) { async onError(error: unknown) {

View File

@ -0,0 +1,26 @@
import { isSafari } from "./isSafari";
export async function writeToClipboard(message: string) {
if (!navigator.clipboard) {
return false;
}
// Safari only allows navigator.clipboard.write with native clipboard items.
try {
if (isSafari()) {
await navigator.clipboard.write([
new ClipboardItem({
"text/plain": new Blob([message], {
type: "text/plain",
}),
}),
]);
} else {
await navigator.clipboard.writeText(message);
}
return true;
} catch (_) {
/* no op */
}
return false;
}