♻️ Refactoring code

This commit is contained in:
Liyas Thomas
2020-01-10 06:27:48 +05:30
parent bf1a143f03
commit 57f7621567
4 changed files with 106 additions and 80 deletions

View File

@@ -1,89 +1,95 @@
const redirectUri = `${ window.location.origin }/`; const redirectUri = `${window.location.origin}/`;
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// GENERAL HELPER FUNCTIONS // GENERAL HELPER FUNCTIONS
// Make a POST request and parse the response as JSON // Make a POST request and parse the response as JSON
const sendPostRequest = async(url, params) => { const sendPostRequest = async (url, params) => {
let body = Object.keys(params).map(key => key + '=' + params[key]).join('&'); let body = Object.keys(params)
.map(key => `${key}=${params[key]}`)
.join("&");
const options = { const options = {
method: 'post', method: "post",
headers: { headers: {
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8' "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
}, },
body body
} };
try { try {
const response = await fetch(url, options); const response = await fetch(url, options);
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (err) { } catch (err) {
console.error('Request failed', err); console.error("Request failed", err);
throw err; throw err;
} }
} };
// Parse a query string into an object // Parse a query string into an object
const parseQueryString = string => { const parseQueryString = string => {
if(string == "") { return {}; } if (string === "") {
let segments = string.split("&").map(s => s.split("=") ); return {};
}
let segments = string.split("&").map(s => s.split("="));
let queryString = {}; let queryString = {};
segments.forEach(s => queryString[s[0]] = s[1]); segments.forEach(s => (queryString[s[0]] = s[1]));
return queryString; return queryString;
} };
// Get OAuth configuration from OpenID Discovery endpoint // Get OAuth configuration from OpenID Discovery endpoint
const getTokenConfiguration = async endpoint => { const getTokenConfiguration = async endpoint => {
const options = { const options = {
method: 'GET', method: "GET",
headers: { headers: {
'Content-type': 'application/json' "Content-type": "application/json"
} }
} };
try { try {
const response = await fetch(endpoint, options); const response = await fetch(endpoint, options);
const config = await response.json(); const config = await response.json();
return config; return config;
} catch (err) { } catch (err) {
console.error('Request failed', err); console.error("Request failed", err);
throw err; throw err;
} }
} };
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// PKCE HELPER FUNCTIONS // PKCE HELPER FUNCTIONS
// Generate a secure random string using the browser crypto functions // Generate a secure random string using the browser crypto functions
const generateRandomString = () => { const generateRandomString = () => {
var array = new Uint32Array(28); const array = new Uint32Array(28);
window.crypto.getRandomValues(array); window.crypto.getRandomValues(array);
return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join(''); return Array.from(array, dec => `0${dec.toString(16)}`.substr(-2)).join("");
} };
// Calculate the SHA256 hash of the input text. // Calculate the SHA256 hash of the input text.
// Returns a promise that resolves to an ArrayBuffer // Returns a promise that resolves to an ArrayBuffer
const sha256 = plain => { const sha256 = plain => {
const encoder = new TextEncoder(); const encoder = new TextEncoder();
const data = encoder.encode(plain); const data = encoder.encode(plain);
return window.crypto.subtle.digest('SHA-256', data); return window.crypto.subtle.digest("SHA-256", data);
} };
// Base64-urlencodes the input string // Base64-urlencodes the input string
const base64urlencode = str => { const base64urlencode = (
// Convert the ArrayBuffer to string using Uint8 array to conver to what btoa accepts. str // Convert the ArrayBuffer to string using Uint8 array to conver to what btoa accepts.
) =>
// btoa accepts chars only within ascii 0-255 and base64 encodes them. // btoa accepts chars only within ascii 0-255 and base64 encodes them.
// Then convert the base64 encoded to base64url encoded // Then convert the base64 encoded to base64url encoded
// (replace + with -, replace / with _, trim trailing =) // (replace + with -, replace / with _, trim trailing =)
return btoa(String.fromCharCode.apply(null, new Uint8Array(str))) btoa(String.fromCharCode.apply(null, new Uint8Array(str)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); .replace(/\+/g, "-")
} .replace(/\//g, "_")
.replace(/=+$/, "");
// Return the base64-urlencoded sha256 hash for the PKCE challenge // Return the base64-urlencoded sha256 hash for the PKCE challenge
const pkceChallengeFromVerifier = async(v) => { const pkceChallengeFromVerifier = async v => {
let hashed = await sha256(v); let hashed = await sha256(v);
return base64urlencode(hashed); return base64urlencode(hashed);
} };
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// OAUTH REQUEST // OAUTH REQUEST
// Initiate PKCE Auth Code flow when requested // Initiate PKCE Auth Code flow when requested
const tokenRequest = async({ const tokenRequest = async ({
oidcDiscoveryUrl, oidcDiscoveryUrl,
grantType, grantType,
authUrl, authUrl,
@@ -91,85 +97,89 @@ const tokenRequest = async({
clientId, clientId,
scope scope
}) => { }) => {
// Check oauth configuration // Check oauth configuration
if (oidcDiscoveryUrl !== '') { if (oidcDiscoveryUrl !== "") {
const { authorization_endpoint, token_endpoint } = await getTokenConfiguration(oidcDiscoveryUrl); const {
authorization_endpoint,
token_endpoint
} = await getTokenConfiguration(oidcDiscoveryUrl);
authUrl = authorization_endpoint; authUrl = authorization_endpoint;
accessTokenUrl = token_endpoint; accessTokenUrl = token_endpoint;
} }
// Store oauth information // Store oauth information
localStorage.setItem('token_endpoint', accessTokenUrl); localStorage.setItem("token_endpoint", accessTokenUrl);
localStorage.setItem('client_id', clientId); localStorage.setItem("client_id", clientId);
// Create and store a random state value // Create and store a random state value
const state = generateRandomString(); const state = generateRandomString();
localStorage.setItem('pkce_state', state); localStorage.setItem("pkce_state", state);
// Create and store a new PKCE code_verifier (the plaintext random secret) // Create and store a new PKCE code_verifier (the plaintext random secret)
const code_verifier = generateRandomString(); const code_verifier = generateRandomString();
localStorage.setItem('pkce_code_verifier', code_verifier); localStorage.setItem("pkce_code_verifier", code_verifier);
// Hash and base64-urlencode the secret to use as the challenge // Hash and base64-urlencode the secret to use as the challenge
const code_challenge = await pkceChallengeFromVerifier(code_verifier); const code_challenge = await pkceChallengeFromVerifier(code_verifier);
// Build the authorization URL // Build the authorization URL
const buildUrl = () => { const buildUrl = () =>
return authUrl `${authUrl + `?response_type=${grantType}`}&client_id=${encodeURIComponent(
+ `?response_type=${grantType}` clientId
+ '&client_id='+encodeURIComponent(clientId) )}&state=${encodeURIComponent(state)}&scope=${encodeURIComponent(
+ '&state='+encodeURIComponent(state) scope
+ '&scope='+encodeURIComponent(scope) )}&redirect_uri=${encodeURIComponent(
+ '&redirect_uri='+encodeURIComponent(redirectUri) redirectUri
+ '&code_challenge='+encodeURIComponent(code_challenge) )}&code_challenge=${encodeURIComponent(
+ '&code_challenge_method=S256' code_challenge
; )}&code_challenge_method=S256`;
}
// Redirect to the authorization server // Redirect to the authorization server
window.location = buildUrl(); window.location = buildUrl();
} };
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// OAUTH REDIRECT HANDLING // OAUTH REDIRECT HANDLING
// Handle the redirect back from the authorization server and // Handle the redirect back from the authorization server and
// get an access token from the token endpoint // get an access token from the token endpoint
const oauthRedirect = async() => { const oauthRedirect = async () => {
let tokenResponse = ''; let tokenResponse = "";
let q = parseQueryString(window.location.search.substring(1)); let q = parseQueryString(window.location.search.substring(1));
// Check if the server returned an error string // Check if the server returned an error string
if(q.error) { if (q.error) {
alert('Error returned from authorization server: '+q.error); alert(`Error returned from authorization server: ${q.error}`);
} }
// If the server returned an authorization code, attempt to exchange it for an access token // If the server returned an authorization code, attempt to exchange it for an access token
if(q.code) { if (q.code) {
// Verify state matches what we set at the beginning // Verify state matches what we set at the beginning
if(localStorage.getItem('pkce_state') != q.state) { if (localStorage.getItem("pkce_state") != q.state) {
alert('Invalid state'); alert("Invalid state");
} else { } else {
try { try {
// Exchange the authorization code for an access token // Exchange the authorization code for an access token
tokenResponse = await sendPostRequest(localStorage.getItem('token_endpoint'), { tokenResponse = await sendPostRequest(
grant_type: 'authorization_code', localStorage.getItem("token_endpoint"),
code: q.code, {
client_id: localStorage.getItem('client_id'), grant_type: "authorization_code",
redirect_uri: redirectUri, code: q.code,
code_verifier: localStorage.getItem('pkce_code_verifier') client_id: localStorage.getItem("client_id"),
}); redirect_uri: redirectUri,
code_verifier: localStorage.getItem("pkce_code_verifier")
}
);
} catch (err) { } catch (err) {
console.log(error.error+'\n\n'+error.error_description); console.log(`${error.error}\n\n${error.error_description}`);
} }
} }
// Clean these up since we don't need them anymore // Clean these up since we don't need them anymore
localStorage.removeItem('pkce_state'); localStorage.removeItem("pkce_state");
localStorage.removeItem('pkce_code_verifier'); localStorage.removeItem("pkce_code_verifier");
localStorage.removeItem('token_endpoint'); localStorage.removeItem("token_endpoint");
localStorage.removeItem('client_id'); localStorage.removeItem("client_id");
return tokenResponse; return tokenResponse;
} }
return tokenResponse; return tokenResponse;
} };
export { tokenRequest, oauthRedirect } export { tokenRequest, oauthRedirect };

View File

@@ -549,8 +549,8 @@ export default {
this.$store.state.postwoman.settings.THEME_CLASS || ""; this.$store.state.postwoman.settings.THEME_CLASS || "";
// Load theme color data from settings, or use default color. // Load theme color data from settings, or use default color.
let color = this.$store.state.postwoman.settings.THEME_COLOR || "#50fa7b"; let color = this.$store.state.postwoman.settings.THEME_COLOR || "#50fa7b";
let vibrant = this.$store.state.postwoman.settings.THEME_COLOR_VIBRANT; let vibrant =
if (vibrant == null) vibrant = true; this.$store.state.postwoman.settings.THEME_COLOR_VIBRANT || true;
document.documentElement.style.setProperty("--ac-color", color); document.documentElement.style.setProperty("--ac-color", color);
document.documentElement.style.setProperty( document.documentElement.style.setProperty(
"--act-color", "--act-color",

View File

@@ -288,7 +288,10 @@
</label> </label>
<div v-if="queryFields.length > 0" class="tab"> <div v-if="queryFields.length > 0" class="tab">
<div v-for="field in queryFields" :key="field.name"> <div v-for="field in queryFields" :key="field.name">
<gql-field :gqlField="field" :jumpTypeCallback="handleJumpToType" /> <gql-field
:gqlField="field"
:jumpTypeCallback="handleJumpToType"
/>
</div> </div>
</div> </div>
@@ -304,7 +307,10 @@
</label> </label>
<div v-if="mutationFields.length > 0" class="tab"> <div v-if="mutationFields.length > 0" class="tab">
<div v-for="field in mutationFields" :key="field.name"> <div v-for="field in mutationFields" :key="field.name">
<gql-field :gqlField="field" :jumpTypeCallback="handleJumpToType" /> <gql-field
:gqlField="field"
:jumpTypeCallback="handleJumpToType"
/>
</div> </div>
</div> </div>
@@ -320,7 +326,10 @@
</label> </label>
<div v-if="subscriptionFields.length > 0" class="tab"> <div v-if="subscriptionFields.length > 0" class="tab">
<div v-for="field in subscriptionFields" :key="field.name"> <div v-for="field in subscriptionFields" :key="field.name">
<gql-field :gqlField="field" :jumpTypeCallback="handleJumpToType" /> <gql-field
:gqlField="field"
:jumpTypeCallback="handleJumpToType"
/>
</div> </div>
</div> </div>
@@ -335,8 +344,15 @@
{{ $t("types") }} {{ $t("types") }}
</label> </label>
<div v-if="gqlTypes.length > 0" class="tab"> <div v-if="gqlTypes.length > 0" class="tab">
<div v-for="type in gqlTypes" :key="type.name" :id="`type_${type.name}`"> <div
<gql-type :gqlType="type" :jumpTypeCallback="handleJumpToType" /> v-for="type in gqlTypes"
:key="type.name"
:id="`type_${type.name}`"
>
<gql-type
:gqlType="type"
:jumpTypeCallback="handleJumpToType"
/>
</div> </div>
</div> </div>
</section> </section>
@@ -572,13 +588,13 @@ export default {
const target = document.getElementById(`type_${rootTypeName}`); const target = document.getElementById(`type_${rootTypeName}`);
if (target) { if (target) {
target.scrollIntoView({ target.scrollIntoView({
behavior: 'smooth' behavior: "smooth"
}); });
} }
}, },
resolveRootType(type) { resolveRootType(type) {
let t = type; let t = type;
while (t.ofType != null) t = t.ofType; while (t.ofType !== null) t = t.ofType;
return t; return t;
}, },
copySchema() { copySchema() {

View File

@@ -75,7 +75,7 @@ export const state = () => ({
export const mutations = { export const mutations = {
applySetting({ settings }, setting) { applySetting({ settings }, setting) {
if ( if (
setting == null || setting === null ||
!(setting instanceof Array) || !(setting instanceof Array) ||
setting.length !== 2 setting.length !== 2
) { ) {