From b77f86bf7f71936475b344867d61010bca1f1c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20St=C4=99pniewski?= Date: Sun, 7 Jun 2020 22:38:12 +0200 Subject: [PATCH] feat(repo): github profile url should be valid (#268) * feat(repo): github profile url should be valid * docs: add k3nsei as a contributor --- .all-contributorsrc | 11 +++++++++ README.md | 4 +++- src/repo/github.js | 5 ++-- src/util/__tests__/url.js | 49 +++++++++++++++++++++++++++++++++++++++ src/util/index.js | 1 + src/util/url.js | 33 ++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 src/util/__tests__/url.js create mode 100644 src/util/url.js diff --git a/.all-contributorsrc b/.all-contributorsrc index a1ffc17c..56b7d7df 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -429,6 +429,17 @@ "contributions": [ "platform" ] + }, + { + "login": "k3nsei", + "name": "Piotr Stępniewski", + "avatar_url": "https://avatars2.githubusercontent.com/u/190422?v=4", + "profile": "https://github.com/k3nsei", + "contributions": [ + "bug", + "code", + "test" + ] } ], "skipCi": true diff --git a/README.md b/README.md index ef78eb48..0adb5bcb 100644 --- a/README.md +++ b/README.md @@ -134,14 +134,16 @@ Thanks goes to these wonderful people
Anand Chowdhary

⚠️ 🐛 💻
Nicolas Goutay

💻
Tyler Krupicka

💻 ⚠️ + +
Stefano Moia

💻
Ilaï Deutel

📦 +
Piotr Stępniewski

🐛 💻 ⚠️ - This project follows the diff --git a/src/repo/github.js b/src/repo/github.js index bde0e930..c1d297be 100644 --- a/src/repo/github.js +++ b/src/repo/github.js @@ -1,6 +1,7 @@ const url = require('url') const pify = require('pify') const request = pify(require('request')) +const { parseHttpUrl, isValidHttpUrl } = require('../util/url') /** * Get the host based on public or enterprise GitHub. @@ -93,7 +94,7 @@ const getUserInfo = function(username, hostname, optionalPrivateToken) { .then(res => { const body = JSON.parse(res.body) - let profile = body.blog || body.html_url + let profile = isValidHttpUrl(body.blog) ? body.blog : body.html_url // Check for authentication required if ( @@ -112,7 +113,7 @@ const getUserInfo = function(username, hostname, optionalPrivateToken) { ) } - profile = profile.startsWith('http') ? profile : `http://${profile}` + profile = parseHttpUrl(profile) return { login: body.login, diff --git a/src/util/__tests__/url.js b/src/util/__tests__/url.js new file mode 100644 index 00000000..50ff6d4d --- /dev/null +++ b/src/util/__tests__/url.js @@ -0,0 +1,49 @@ +import url from '../url'; + +test(`Result of protocol validation should be true`, () => { + expect(url.isHttpProtocol('http:')).toBe(true) + expect(url.isHttpProtocol('https:')).toBe(true) +}) + +test(`Result of protocol validation should be false`, () => { + expect(url.isHttpProtocol('ftp:')).toBe(false) +}) + +test(`Result of url validation should be true`, () => { + expect(url.isValidHttpUrl('https://api.github.com/users/octocat')).toBe(true) +}) + +test(`Result of url validation should be false when url uses wrong protocol`, () => { + expect(url.isValidHttpUrl('git://git@github.com:all-contributors/all-contributors-cli.git')).toBe(false) +}) + +test(`Result of url validation should be false when input isn't url`, () => { + expect(url.isValidHttpUrl('github-octocat')).toBe(false) +}) + +test(`Result of parsed url should be equal`, () => { + const input = 'https://api.github.com/users/octocat' + const expected = 'https://api.github.com/users/octocat' + expect(url.parseHttpUrl(input)).toBe(expected) +}) + +test(`Result of parsed url without protocol should be equal`, () => { + const input = 'example.com' + const expected = 'http://example.com/' + expect(url.parseHttpUrl(input)).toBe(expected) +}) + +test(`Throw an error when parsed input isn't a string`, () => { + const input = 123 + expect(url.parseHttpUrl.bind(null, input)).toThrowError('input must be a string') +}) + +test(`Throw an error when parsed url has wrong protocol`, () => { + const input = 'ftp://domain.xyz' + expect(url.parseHttpUrl.bind(null, input)).toThrowError('Provided URL has an invalid protocol') +}) + +test(`Throw an error when parsed input isn't a URL`, () => { + const input = 'some string' + expect(url.parseHttpUrl.bind(null, input)).toThrowError('Invalid URL: http://some string') +}) diff --git a/src/util/index.js b/src/util/index.js index a58592d7..9cb53145 100644 --- a/src/util/index.js +++ b/src/util/index.js @@ -3,4 +3,5 @@ module.exports = { contributionTypes: require('./contribution-types'), git: require('./git'), markdown: require('./markdown'), + url: require('./url'), } diff --git a/src/util/url.js b/src/util/url.js new file mode 100644 index 00000000..348cbdda --- /dev/null +++ b/src/util/url.js @@ -0,0 +1,33 @@ +function isHttpProtocol(input) { + return new RegExp('^https?\\:?$').test(input) +} + +function isValidHttpUrl(input) { + try { + const url = new URL(input) + + return isHttpProtocol(url.protocol) + } catch (e) { + return false + } +} + +function parseHttpUrl(input) { + if (typeof input !== 'string') { + throw new TypeError('input must be a string') + } + + const url = new URL(new RegExp('^\\w+\\:\\/\\/').test(input) ? input : `http://${input}`) + + if (!isHttpProtocol(url.protocol)) { + throw new TypeError('Provided URL has an invalid protocol') + } + + return url.toString() +} + +module.exports = { + isHttpProtocol, + isValidHttpUrl, + parseHttpUrl +}