Skip to content

Commit

Permalink
fix(api-gitlab-v4): workaround for gitlab redirect_uri issue (close m…
Browse files Browse the repository at this point in the history
  • Loading branch information
mohan43u committed Oct 10, 2020
1 parent 6549d84 commit 6be27f6
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 15 deletions.
73 changes: 63 additions & 10 deletions packages/@vssue/api-gitlab-v4/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,19 @@ describe('methods', () => {
delete window.location;

const url = 'https://vssue.js.org';
window.location = { href: url } as any;
window.location = { href: url, origin: url } as any;
const stateobj = {
state: options.state,
redirect_uri: window.location.pathname,
};
const stateobj64 = encodeURIComponent(btoa(JSON.stringify(stateobj)));
API.redirectAuth();
expect(window.location.href).toBe(
`${baseURL}/oauth/authorize?client_id=${
options.clientId
}&redirect_uri=${encodeURIComponent(url)}&response_type=token&state=${
options.state
}`
}&redirect_uri=${encodeURIComponent(
url
)}&response_type=token&state=${stateobj64}`
);

// reset `window.location`
Expand All @@ -79,28 +84,76 @@ describe('methods', () => {
});

test('with matched state', async () => {
const url = `https://vssue.js.org/#access_token=${mockToken}&state=${options.state}`;
const initial_uri = 'https://vssue.js.org/';
const stateobj = {
state: options.state,
};
const stateobj64 = encodeURIComponent(btoa(JSON.stringify(stateobj)));
const url = `${initial_uri}#access_token=${mockToken}&state=${stateobj64}`;
window.history.replaceState(null, '', url);
const token = await API.handleAuth();
expect(window.location.href).toBe('https://vssue.js.org/');
expect(window.location.href).toBe(initial_uri);
expect(token).toBe(mockToken);
});

test('with unmatched state', async () => {
const url = `https://vssue.js.org/#access_token=${mockToken}&state=${options.state}-unmatched`;
const initial_uri = 'https://vssue.js.org/';
const stateobj = {
state: `${options.state}-unmatched`,
};
const stateobj64 = encodeURIComponent(btoa(JSON.stringify(stateobj)));
const url = `${initial_uri}#access_token=${mockToken}&state=${stateobj64}`;
window.history.replaceState(null, '', url);
const token = await API.handleAuth();
expect(window.location.href).toBe(url);
expect(window.location.href).toBe(initial_uri);
expect(token).toBe(null);
});

test('with extra hash', async () => {
const url = `https://vssue.js.org/#access_token=${mockToken}&state=${options.state}&extra=hash`;
const initial_uri = 'https://vssue.js.org/';
const stateobj = {
state: options.state,
};
const stateobj64 = encodeURIComponent(btoa(JSON.stringify(stateobj)));
const url = `https://vssue.js.org/#access_token=${mockToken}&state=${stateobj64}&extra=hash`;
window.history.replaceState(null, '', url);
const token = await API.handleAuth();
expect(window.location.href).toBe('https://vssue.js.org/#extra=hash');
expect(window.location.href).toBe(`${initial_uri}#extra=hash`);
expect(token).toBe(mockToken);
});

test('with redirect_uri', async () => {
// to make `window.location` writable
const location = window.location;
delete window.location;

const stateobj = {
state: options.state,
redirect_uri: '/deep/path',
};
const stateobj64 = encodeURIComponent(btoa(JSON.stringify(stateobj)));
window.location = {
href: '',
origin: '',
search: '',
hash: `#access_token=${mockToken}&state=${stateobj64}&extra=hash`,
assign: (a, b, c) => {
window.location.href = c;
},
} as any;
const token = await API.handleAuth();
delete stateobj.redirect_uri;
const stateobj64result = encodeURIComponent(
btoa(JSON.stringify(stateobj))
);
expect(window.location.href).toBe(
`/deep/path#extra=hash&access_token=${mockToken}&state=${stateobj64result}`
);
expect(token).toBe(mockToken);

// reset `window.location`
window.location = location;
});
});

test('getUser', async () => {
Expand Down
32 changes: 27 additions & 5 deletions packages/@vssue/api-gitlab-v4/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,17 @@ export default class GitlabV4 implements VssueAPI.Instance {
* @see https://docs.gitlab.com/ce/api/oauth2.html#1-requesting-authorization-code
*/
redirectAuth(): void {
const stateobj = {
state: this.state,
redirect_uri: window.location.pathname,
};
window.location.href = buildURL(
concatURL(this.baseURL, 'oauth/authorize'),
{
client_id: this.clientId,
redirect_uri: window.location.href,
redirect_uri: window.location.origin,
response_type: 'token',
state: this.state,
state: btoa(JSON.stringify(stateobj)),
}
);
}
Expand All @@ -112,10 +116,10 @@ export default class GitlabV4 implements VssueAPI.Instance {
*/
async handleAuth(): Promise<VssueAPI.AccessToken> {
const hash = parseQuery(window.location.hash.slice(1));
if (!hash.access_token || hash.state !== this.state) {
return null;
}
const stateobj = JSON.parse(atob(hash.state ? hash.state : btoa('{}')));
const accessToken = hash.access_token;
const token_type = hash.token_type;
const expires_in = hash.expires_in;
delete hash.access_token;
delete hash.token_type;
delete hash.expires_in;
Expand All @@ -126,6 +130,24 @@ export default class GitlabV4 implements VssueAPI.Instance {
window.location.search
}${newHash}`;
window.history.replaceState(null, '', replaceURL);
if (accessToken == null) {
return null;
}
if (stateobj == null || stateobj.state !== this.state) {
return null;
}
if (stateobj.redirect_uri != null && stateobj.redirect_uri !== '/') {
const redirect_uri = stateobj.redirect_uri;
delete stateobj.redirect_uri;
hash.access_token = accessToken;
hash.token_type = token_type;
hash.expores_in = expires_in;
hash.state = btoa(JSON.stringify(stateobj));
const hashString = buildQuery(hash);
window.location.href = `${getCleanURL(redirect_uri)}${
window.location.search
}#${hashString}`;
}
return accessToken;
}

Expand Down

0 comments on commit 6be27f6

Please sign in to comment.