Skip to content

Commit

Permalink
feat: create 0-config authentication (IT JUST WORKS 🔥🔥🔥)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kipras Melnikovas committed Aug 23, 2020
1 parent ef17f7e commit fd43b7c
Show file tree
Hide file tree
Showing 21 changed files with 327 additions and 49 deletions.
40 changes: 33 additions & 7 deletions source/Features.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
import domLoaded from "dom-loaded";

import { pageLoaded } from "./utils/pageLoaded";
// eslint-disable-next-line import/no-cycle
import { Config, getConfig } from "./utils/config";
// eslint-disable-next-line import/no-cycle
import { needsToWaitForApi } from "./utils/needsToWaitForApi";
// eslint-disable-next-line import/no-cycle
import { apiLoaded } from "./utils/apiLoaded";

export type Feature = (config: Config) => any;
export type FeatureProps = Config & {};

export type Feature = (props: FeatureProps) => any;

export interface FeatureDescription {
id: string;
feature: Feature;
waitForDomLoaded?: boolean;
waitForPageLoaded?: boolean;
needsApi?: boolean;
}

class Features {
private __addedFeatures: FeatureDescription[] = [];

add(ctx: FeatureDescription) {
add(ctx: FeatureDescription): void {
this.__addedFeatures.push(ctx);
}

Expand All @@ -24,21 +34,37 @@ class Features {
loadAll(): void {
const config = getConfig();

for (const { id, feature, waitForDomLoaded } of this.getAll()) {
for (const { id, feature, waitForDomLoaded, waitForPageLoaded, needsApi } of this.getAll()) {
if (config.features[id] === false) {
console.log(`⏭ skipping feature because it's disabled in config, id: \`${id}\``);
continue;
}

try {
const featureProps: FeatureProps = { ...config };

const requirements: Promise<any>[] = [];

if (waitForDomLoaded) {
(async () => {
await domLoaded;
feature(config);
requirements.push(domLoaded);
}

if (waitForPageLoaded) {
requirements.push(pageLoaded);
}

if (needsApi && needsToWaitForApi()) {
requirements.push(apiLoaded);
}

if (requirements.length > 0) {
(async (): Promise<void> => {
await Promise.all(requirements);
feature(featureProps);
console.log(`✅ (⏱) feature loaded (after dom loaded), id: \`${id}\``);
})();
} else {
feature(config);
feature(featureProps);
console.log(`✅ feature loaded (instantly), id: \`${id}\``);
}
} catch (e) {
Expand Down
1 change: 0 additions & 1 deletion source/background.ts

This file was deleted.

1 change: 1 addition & 0 deletions source/features/add-custom-label-pickers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ features.add({
id: "add-custom-label-pickers",
feature: addCustomLabelPickers,
waitForDomLoaded: true,
needsApi: true,
});
1 change: 0 additions & 1 deletion source/index.ts

This file was deleted.

26 changes: 19 additions & 7 deletions source/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 2,
"name": "Refined GitLab",
"version": "0.0.0",
"description": "Makes GitLab just a tad bit better",
"homepage_url": "https://github.com/kiprasmel/refined-gitlab",
"description": "🏷 Make your GitLab experience better!",
"homepage_url": "https://gitlab.com/kiprasmel/refined-gitlab",
"minimum_chrome_version": "74",
"applications": {
"gecko": {
Expand All @@ -12,19 +12,31 @@
}
},
"icons": {},
"permissions": ["storage"],
"permissions": [
"storage",
"cookies",
"tabs",
"<all_urls>"
],
"options_ui": {
"chrome_style": true,
"page": "options.html"
},
"background": {
"persistent": false,
"scripts": ["browser-polyfill.min.js", "background.js"]
"scripts": [
"browser-polyfill.min.js",
"background.js"
]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["index.js"]
"matches": [
"<all_urls>"
],
"js": [
"browser-polyfill.min.js",
"content.js"
]
}
]
}
10 changes: 7 additions & 3 deletions source/options.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import optionsStorage from "./options-storage";
import optionsStorage from "./scripts-background/options-storage";

optionsStorage.syncForm("#options-form");

const rangeInputs = [...document.querySelectorAll('input[type="range"][name^="color"]')];
const numberInputs = [...document.querySelectorAll('input[type="number"][name^="color"]')];
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
const rangeInputs = [...document.querySelectorAll<HTMLInputElement>('input[type="range"][name^="color"]')];
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
const numberInputs = [...document.querySelectorAll<HTMLInputElement>('input[type="number"][name^="color"]')];
const output = document.querySelector(".color-output");

function updateColor(): void {
Expand Down
3 changes: 3 additions & 0 deletions source/scripts-background/background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// import "./options-storage";
import "./gitlab-session-cookie-sync";
// import "./set-global-var";
69 changes: 69 additions & 0 deletions source/scripts-background/gitlab-session-cookie-sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Retrieve any previously set cookie and send to content script
*
* https://github.com/mdn/webextensions-examples/blob/master/cookie-bg-picker/background_scripts/background.js
*/

async function getActiveTab(): Promise<browser.tabs.Tab> {
return await browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => tabs[0]);
}

interface MessagePayload {
gitlabSessionToken: string | undefined;
success: boolean;
reason?: string;
}

async function sendMessage(
tabId: number,
messagePayload: MessagePayload,
options?: browser.tabs._SendMessageOptions | undefined
): Promise<void> {
await browser.tabs.sendMessage(tabId, messagePayload, options);
}

async function gitlabSessionCookieSync(): Promise<void> {
try {
const tab = await getActiveTab();

if (tab.id === undefined) {
return;
}

if (!tab?.url) {
await sendMessage(tab.id, {
gitlabSessionToken: undefined,
success: false,
reason: "Cannot update cookies (tab's **URL** not found)",
});

return;
}

/** get any previously set cookie for the current tab */
const cookie: browser.cookies.Cookie | null = await browser.cookies.get({
url: tab.url,
name: "_gitlab_session",
});

if (!cookie) {
await sendMessage(tab.id, {
gitlabSessionToken: undefined,
success: false,
reason: "Cannot update cookies (cookie was falsy)",
});

return;
}

await sendMessage(tab.id, { gitlabSessionToken: cookie.value, success: true });
} catch (e) {
console.error(e);
throw e;
}
}

/** update when the tab is updated */
browser.tabs.onUpdated.addListener(gitlabSessionCookieSync);
/** update when the tab is activated */
browser.tabs.onActivated.addListener(gitlabSessionCookieSync);
File renamed without changes.
2 changes: 2 additions & 0 deletions source/scripts-content/content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import "./inject-native-auth-into-api";
import "./refined-gitlab";
32 changes: 32 additions & 0 deletions source/scripts-content/inject-native-auth-into-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { updateApiVariable } from "../utils/api";
import { getConfig } from "../utils/config";
import { getCSRFData } from "../utils/getCSRFData";

function injectNativeAuthIntoApi(request, _sender, _sendResponse): void {
const { authKind } = getConfig();

if (authKind !== "native") {
return;
}

const { gitlabSessionToken } = request;

if (gitlabSessionToken) {
// console.log("`gitlabSessionToken` present - creating new api");

const { key: gitlabCSRFTokenKey, value: gitlabCSRFTokenValue } = getCSRFData();

updateApiVariable({
kind: "native",
options: {
nativeAuth: {
gitlabSessionCookieValue: gitlabSessionToken,
gitlabCSRFTokenKey,
gitlabCSRFTokenValue,
},
},
});
}
}

browser.runtime.onMessage.addListener(injectNativeAuthIntoApi);
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import select from "select-dom";

import { globalInit } from "./utils/globalInit";
// import "./utils/api";
import { globalInit } from "../utils/globalInit";

import "./styles/default.scss";
import "./styles/cluster.scss";
import "../styles/default.scss";
import "../styles/cluster.scss";

/** leggo */
import "./features/add-custom-label-pickers";
import "./features/always-expand-sidebar";
import "../features/add-custom-label-pickers";
import "../features/always-expand-sidebar";
import "../features/show-total-commit-count";

globalInit();

Expand Down
53 changes: 47 additions & 6 deletions source/utils/api.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,54 @@
// // import { Gitlab } from "@gitbeaker/core"; /** all imports utterly broken */
import { Gitlab } from "../../gitbeaker/packages/gitbeaker-browser/src";
// eslint-disable-next-line import/no-cycle
import { getConfig } from "./config";
import { NativeAuth as GitbeakerNativeAuth } from "../../gitbeaker/packages/gitbeaker-core/src/infrastructure/BaseService";
// import { setGlobalVar } from "./setGlobalVar";

/**
* https://github.com/jdalrymple/gitbeaker
*/

export const api = new Gitlab({
token: getConfig().apiToken,
host: getConfig().hostUrl,
});
export interface NativeAuth {
kind: "native";
options: {
nativeAuth: GitbeakerNativeAuth;
};
}

export interface APITokenAuth {
kind: "apiToken";
options: {
oauthToken: string;
host: string;
};
}

export type Auth = NativeAuth | APITokenAuth;

export type AuthKind = Auth["kind"];

// eslint-disable-next-line import/no-mutable-exports
let api: ReturnType<typeof createApi>;

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export const createApi = (auth: Auth) => {
console.log("createApi, auth =", auth);

return new Gitlab({ ...auth.options });
};

export const updateApiVariable = (auth: Auth) => {
console.log("updateApiVariable", api);

api = createApi(auth);

/** broken */
// (window as any).api = api;

// // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// // @ts-ignore
// (window as any).api = cloneInto(api, window, { cloneFunctions: true });

return api;
};

export { api };
15 changes: 15 additions & 0 deletions source/utils/apiLoaded.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { needsToWaitForApi } from "./needsToWaitForApi";

export const apiLoaded = new Promise((resolve) => {
if (!needsToWaitForApi()) {
resolve();
}

browser.runtime.onMessage.addListener((request, _sender, _sendResponse) => {
const { gitlabSessionToken } = request;

if (gitlabSessionToken) {
resolve();
}
});
});
Loading

0 comments on commit fd43b7c

Please sign in to comment.