Skip to content

Commit

Permalink
Fix #915: Add button to copy authentication header
Browse files Browse the repository at this point in the history
  • Loading branch information
leplatrem committed May 28, 2019
1 parent b4acd79 commit 89bd0a7
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 10 deletions.
2 changes: 1 addition & 1 deletion css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ h1 {
padding-top: .3em;
}

.user-info a {
.user-info a.spaced {
margin-left: 1em;
}

Expand Down
7 changes: 7 additions & 0 deletions src/actions/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
SESSION_BUCKETS_REQUEST,
SESSION_BUCKETS_SUCCESS,
SESSION_AUTHENTICATED,
SESSION_COPY_AUTHENTICATION_HEADER,
SESSION_LOGOUT,
} from "../constants";

Expand Down Expand Up @@ -110,6 +111,12 @@ export function setAuthenticated(): {
return { type: SESSION_AUTHENTICATED };
}

export function copyAuthenticationHeader(): {
type: "SESSION_COPY_AUTHENTICATION_HEADER",
} {
return { type: SESSION_COPY_AUTHENTICATION_HEADER };
}

export function logout(): {
type: "SESSION_LOGOUT",
} {
Expand Down
6 changes: 4 additions & 2 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import KintoClient from "kinto-http";

let client: ?KintoClient;

function getAuthHeader(auth: AuthData): ?string {
switch (auth.authType) {
export function getAuthHeader(auth: AuthData): ?string {
// For openid, `authType` can be suffixed (eg. `"openid-auth0"`).
const authType = auth.authType.split("-")[0];
switch (authType) {
case "fxa": {
const { token } = auth.credentials;
return `Bearer ${token}`;
Expand Down
25 changes: 20 additions & 5 deletions src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,34 @@ function UserInfo({ session }) {
);
}

function SessionInfoBar({ session, logout }) {
function SessionInfoBar({ session, logout, copyAuthenticationHeader }) {
const {
serverInfo: { url, project_name, project_docs },
} = session;
return (
<div className="session-info-bar">
<h1 className="kinto-admin-title">{project_name}</h1>
<span className="user-info">
<UserInfo session={session} /> on <strong>{url}</strong>{" "}
<UserInfo session={session} />
on <strong>{url}</strong>{" "}
<a
href=""
className="btn btn-xs btn-link"
title="Copy authentication header"
onClick={event =>
event.preventDefault() || copyAuthenticationHeader()
}>
<i className="glyphicon glyphicon-copy" />
</a>
<a
href={project_docs}
target="_blank"
className="btn btn-xs btn-default project-docs">
className="spaced btn btn-xs btn-default project-docs">
<i className="glyphicon glyphicon-question-sign" /> Documentation
</a>
<a
href=""
className="btn btn-xs btn-success btn-logout"
className="spaced btn btn-xs btn-success btn-logout"
onClick={event => event.preventDefault() || logout()}>
<i className="glyphicon glyphicon-log-out" /> Logout
</a>
Expand Down Expand Up @@ -94,6 +104,7 @@ export type Props = {
export default class App extends PureComponent<Props> {
render() {
const {
copyAuthenticationHeader,
session,
logout,
notificationList,
Expand All @@ -111,7 +122,11 @@ export default class App extends PureComponent<Props> {
return (
<div>
{session.authenticated && (
<SessionInfoBar session={session} logout={logout} />
<SessionInfoBar
session={session}
logout={logout}
copyAuthenticationHeader={copyAuthenticationHeader}
/>
)}
<div className="container-fluid main">
<div className="row">
Expand Down
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const SESSION_AUTHENTICATED = "SESSION_AUTHENTICATED";
export const SESSION_BUCKETS_REQUEST = "SESSION_BUCKETS_REQUEST";
export const SESSION_BUCKETS_SUCCESS = "SESSION_BUCKETS_SUCCESS";
export const SESSION_BUSY = "SESSION_BUSY";
export const SESSION_COPY_AUTHENTICATION_HEADER =
"SESSION_COPY_AUTHENTICATION_HEADER";
export const SESSION_LOGOUT = "SESSION_LOGOUT";
export const SESSION_SERVER_CHANGE = "SESSION_SERVER_CHANGE";
export const SESSION_GET_SERVERINFO = "SESSION_GET_SERVERINFO";
Expand Down
5 changes: 5 additions & 0 deletions src/sagas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export default function* rootSaga(
takeEvery(c.SESSION_GET_SERVERINFO, sessionSagas.getServerInfo, getState),
takeEvery(c.SESSION_BUCKETS_REQUEST, sessionSagas.listBuckets, getState),
takeEvery(c.SESSION_LOGOUT, sessionSagas.sessionLogout, getState),
takeEvery(
c.SESSION_COPY_AUTHENTICATION_HEADER,
sessionSagas.sessionCopyAuthenticationHeader,
getState
),
// route
takeEvery(c.ROUTE_REDIRECT, routeSagas.routeRedirect, getState),
takeEvery(c.ROUTE_UPDATED, routeSagas.routeUpdated, getState),
Expand Down
20 changes: 18 additions & 2 deletions src/sagas/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import * as notificationActions from "../actions/notifications";
import * as actions from "../actions/session";
import * as historyActions from "../actions/history";
import { DEFAULT_SERVERINFO } from "../reducers/session";
import { clone, getAuthLabel } from "../utils";
import { getClient, setupClient, resetClient } from "../client";
import { clone, getAuthLabel, copyToClipboard } from "../utils";
import { getClient, setupClient, resetClient, getAuthHeader } from "../client";

export function* serverChange(): SagaGen {
yield put(actions.serverInfoSuccess(DEFAULT_SERVERINFO));
Expand Down Expand Up @@ -161,6 +161,22 @@ export function* sessionLogout(
yield call(clearSession);
}

export function* sessionCopyAuthenticationHeader(
getState: GetStateFn,
action: ActionType<typeof actions.copyAuthenticationHeader>
): SagaGen {
const {
session: { auth },
} = getState();
const authHeader = getAuthHeader(auth);
yield call(copyToClipboard, authHeader);
yield put(
notificationActions.notifySuccess("Header copied to clipboard", {
persistent: false,
})
);
}

export function expandBucketsCollections(
buckets: BucketEntry[],
permissions: PermissionEntry[]
Expand Down
12 changes: 12 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,15 @@ export function parseHistoryFilters(s: string): HistoryFilters {
}
return ret;
}

/**
* Copy specified string to OS clipboard.
*/
export async function copyToClipboard(s: string) {
const { state } = await navigator.permissions.query({
name: "clipboard-write",
});
if (state == "granted" || state == "prompt") {
await navigator.clipboard.writeText(s);
}
}

0 comments on commit 89bd0a7

Please sign in to comment.