mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-01-07 09:03:27 -05:00
Merge pull request from GHSA-6c37-r62q-7xf4
This commit is contained in:
@@ -234,11 +234,43 @@ const updatePrivacyTerms = (req, res, next) => {
|
||||
);
|
||||
};
|
||||
|
||||
function updateMySocials(...args) {
|
||||
const buildUpdate = body =>
|
||||
_.pick(body, ['githubProfile', 'linkedin', 'twitter', 'website']);
|
||||
const validate = update =>
|
||||
Object.values(update).every(x => typeof x === 'string');
|
||||
const allowedSocialsAndDomains = {
|
||||
githubProfile: 'github.com',
|
||||
linkedin: 'linkedin.com',
|
||||
twitter: 'twitter.com',
|
||||
website: ''
|
||||
};
|
||||
|
||||
const socialVals = Object.keys(allowedSocialsAndDomains);
|
||||
|
||||
export function updateMySocials(...args) {
|
||||
const buildUpdate = body => _.pick(body, socialVals);
|
||||
const validate = update => {
|
||||
// Socials should point to their respective domains
|
||||
// or be empty strings
|
||||
return Object.keys(update).every(key => {
|
||||
const val = update[key];
|
||||
if (val === '') {
|
||||
return true;
|
||||
}
|
||||
if (key === 'website') {
|
||||
return isURL(val, { require_protocol: true });
|
||||
}
|
||||
|
||||
const domain = allowedSocialsAndDomains[key];
|
||||
|
||||
try {
|
||||
const url = new URL(val);
|
||||
const topDomain = url.hostname.split('.').slice(-2);
|
||||
if (topDomain.length === 2) {
|
||||
return topDomain.join('.') === domain;
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
createUpdateUserProperties(
|
||||
buildUpdate,
|
||||
validate,
|
||||
|
||||
111
api-server/src/server/boot_tests/settings.test.js
Normal file
111
api-server/src/server/boot_tests/settings.test.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { updateMySocials } from '../boot/settings';
|
||||
|
||||
export const mockReq = opts => {
|
||||
const req = {};
|
||||
return { ...req, ...opts };
|
||||
};
|
||||
|
||||
export const mockRes = opts => {
|
||||
const res = {};
|
||||
res.status = jest.fn().mockReturnValue(res);
|
||||
res.json = jest.fn().mockReturnValue(res);
|
||||
res.redirect = jest.fn().mockReturnValue(res);
|
||||
res.set = jest.fn().mockReturnValue(res);
|
||||
res.clearCookie = jest.fn().mockReturnValue(res);
|
||||
res.cookie = jest.fn().mockReturnValue(res);
|
||||
return { ...res, ...opts };
|
||||
};
|
||||
|
||||
describe('boot/settings', () => {
|
||||
describe('updateMySocials', () => {
|
||||
it('does not allow non-github domain in GitHub social', () => {
|
||||
const req = mockReq({
|
||||
user: {},
|
||||
body: {
|
||||
githubProfile: 'https://www.almost-github.com'
|
||||
}
|
||||
});
|
||||
const res = mockRes();
|
||||
const next = jest.fn();
|
||||
updateMySocials(req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('does not allow non-linkedin domain in LinkedIn social', () => {
|
||||
const req = mockReq({
|
||||
user: {},
|
||||
body: {
|
||||
linkedin: 'https://www.freecodecamp.org'
|
||||
}
|
||||
});
|
||||
const res = mockRes();
|
||||
const next = jest.fn();
|
||||
updateMySocials(req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('does not allow non-twitter domain in Twitter social', () => {
|
||||
const req = mockReq({
|
||||
user: {},
|
||||
body: {
|
||||
twitter: 'https://www.freecodecamp.org'
|
||||
}
|
||||
});
|
||||
const res = mockRes();
|
||||
const next = jest.fn();
|
||||
updateMySocials(req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(403);
|
||||
});
|
||||
|
||||
it('allows empty string in any social', () => {
|
||||
const req = mockReq({
|
||||
user: {
|
||||
updateAttributes: (_, cb) => cb()
|
||||
},
|
||||
body: {
|
||||
twitter: '',
|
||||
linkedin: '',
|
||||
githubProfile: '',
|
||||
website: ''
|
||||
}
|
||||
});
|
||||
const res = mockRes();
|
||||
const next = jest.fn();
|
||||
updateMySocials(req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
});
|
||||
|
||||
it('allows any valid link in website social', () => {
|
||||
const req = mockReq({
|
||||
user: {
|
||||
updateAttributes: (_, cb) => cb()
|
||||
},
|
||||
body: {
|
||||
website: 'https://www.freecodecamp.org'
|
||||
}
|
||||
});
|
||||
const res = mockRes();
|
||||
const next = jest.fn();
|
||||
updateMySocials(req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
});
|
||||
|
||||
it('allows valid links with sub-domains to pass', () => {
|
||||
const req = mockReq({
|
||||
user: {
|
||||
updateAttributes: (_, cb) => cb()
|
||||
},
|
||||
body: {
|
||||
githubProfile: 'https://www.gist.github.com',
|
||||
linkedin: 'https://www.linkedin.com/freecodecamp',
|
||||
twitter: 'https://www.twitter.com/freecodecamp',
|
||||
website: 'https://www.example.freecodecamp.org'
|
||||
}
|
||||
});
|
||||
const res = mockRes();
|
||||
const next = jest.fn();
|
||||
updateMySocials(req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user