Skip to content

Commit c78c25f

Browse files
committed
Fix code scanning alert - Use of externally-controlled format string
Related to #2 --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/Coveros-GitHub-Sandbox/demo-codeveros/issues/2?shareId=XXXX-XXXX-XXXX-XXXX).
1 parent a0d1017 commit c78c25f

File tree

5 files changed

+116
-11
lines changed

5 files changed

+116
-11
lines changed

services/auth-service/nodejs/src/lib/controller.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@ const TokenHandler = require('./token-handler');
44

55
const tokenHandler = new TokenHandler(process.env.JWT_TOKEN);
66

7+
function validateRequestBody(body) {
8+
if (!body || typeof body !== 'object') {
9+
return false;
10+
}
11+
return true;
12+
}
13+
714
exports.signToken = async ctx => {
815
const logger = ctx.codeveros.logger;
916
logger.debug('Creating token');
1017
const { payload } = ctx.request.body;
18+
if (!validateRequestBody(ctx.request.body)) {
19+
logger.debug('Invalid request body');
20+
ctx.throw(400, 'Invalid request body');
21+
}
1122
const token = await tokenHandler.sign(payload);
1223
logger.debug('Token created');
1324
ctx.body = { token };
@@ -17,6 +28,10 @@ exports.verifyToken = async ctx => {
1728
const logger = ctx.codeveros.logger;
1829
const values = ctx.request.body;
1930
logger.debug('Verifying token');
31+
if (!validateRequestBody(ctx.request.body)) {
32+
logger.debug('Invalid request body');
33+
ctx.throw(400, 'Invalid request body');
34+
}
2035
if (values && values.token) {
2136
try {
2237
const payload = await tokenHandler.verify(values.token);

services/auth-service/nodejs/src/lib/token-handler.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@ module.exports = class TokenHandler {
55
this.secret = secret;
66
}
77

8+
validatePayload(payload) {
9+
if (!payload || typeof payload !== 'object') {
10+
return false;
11+
}
12+
return true;
13+
}
14+
815
sign (payload) {
916
return new Promise((resolve, reject) => {
17+
if (!this.validatePayload(payload)) {
18+
return reject(new Error('Invalid payload'));
19+
}
1020
jwt.sign(payload, this.secret, (err, token) => {
1121
return err ? reject(err) : resolve(token);
1222
});
@@ -16,7 +26,13 @@ module.exports = class TokenHandler {
1626
verify (token) {
1727
return new Promise((resolve, reject) => {
1828
jwt.verify(token, this.secret, (err, payload) => {
19-
return err ? reject(err) : resolve(payload);
29+
if (err) {
30+
return reject(err);
31+
}
32+
if (!this.validatePayload(payload)) {
33+
return reject(new Error('Invalid payload'));
34+
}
35+
return resolve(payload);
2036
});
2137
});
2238
}

services/gateway/nodejs/src/lib/api-docs.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,26 @@ const baseSpec = {
3030
security: [{ bearerAuth: [] }]
3131
};
3232

33+
const allowedUrls = [
34+
'http://user-service-url/api/docs',
35+
'http://training-service-url/api/docs'
36+
];
37+
38+
function validateUrl(url) {
39+
return allowedUrls.includes(url);
40+
}
41+
3342
module.exports = opts => async (req, res) => {
43+
const userServiceUrl = `${opts.userServiceUrl}/api/docs`;
44+
const trainingServiceUrl = `${opts.trainingServiceUrl}/api/docs`;
45+
46+
if (!validateUrl(userServiceUrl) || !validateUrl(trainingServiceUrl)) {
47+
return res.status(400).send('Invalid URL');
48+
}
49+
3450
const [userSpec, trainingSpec] = await Promise.all([
35-
unirest.get(`${opts.userServiceUrl}/api/docs`),
36-
unirest.get(`${opts.trainingServiceUrl}/api/docs`)
51+
unirest.get(userServiceUrl),
52+
unirest.get(trainingServiceUrl)
3753
]);
3854

3955
let specFailure = false;

services/gateway/nodejs/src/lib/authentication.js

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
const unirest = require('unirest');
22

3+
const allowedUrls = [
4+
'http://auth-service-url/api/auth/signToken',
5+
'http://auth-service-url/api/auth/verifyToken',
6+
'http://user-service-url/api/user',
7+
'http://user-service-url/api/user/login'
8+
];
9+
10+
function validateUrl(url) {
11+
return allowedUrls.includes(url);
12+
}
13+
314
module.exports = opts => {
415
async function signToken (payload) {
516
try {
17+
const url = `${opts.authServiceUrl}/api/auth/signToken`;
18+
if (!validateUrl(url)) {
19+
console.log('Invalid URL');
20+
return;
21+
}
622
const tokenRes = await unirest
7-
.post(`${opts.authServiceUrl}/api/auth/signToken`).type('json').send({ payload });
23+
.post(url).type('json').send({ payload });
824

925
if (!tokenRes) {
1026
console.log('Did not receive a response when attempting to sign JWT token');
@@ -34,7 +50,12 @@ module.exports = opts => {
3450

3551
let createUserRes;
3652
try {
37-
createUserRes = await unirest.post(`${opts.userServiceUrl}/api/user`).type('json').send(req.body);
53+
const url = `${opts.userServiceUrl}/api/user`;
54+
if (!validateUrl(url)) {
55+
console.log('Invalid URL');
56+
return sendError();
57+
}
58+
createUserRes = await unirest.post(url).type('json').send(req.body);
3859
} catch (err) {
3960
console.error('Failed to create user record in User service: ', err);
4061
return sendError();
@@ -74,8 +95,13 @@ module.exports = opts => {
7495
}
7596

7697
try {
98+
const url = `${opts.userServiceUrl}/api/user/login`;
99+
if (!validateUrl(url)) {
100+
console.log('Invalid URL');
101+
return sendLoginError();
102+
}
77103
const loginRes = await unirest
78-
.post(`${opts.userServiceUrl}/api/user/login`)
104+
.post(url)
79105
.type('json')
80106
.send({ username, password });
81107

@@ -121,8 +147,13 @@ module.exports = opts => {
121147
const splitAuth = authHeader.split(' ');
122148
if (Array.isArray(splitAuth) && splitAuth.length >= 2 && splitAuth[0] === 'Bearer') {
123149
try {
150+
const url = `${opts.authServiceUrl}/api/auth/verifyToken`;
151+
if (!validateUrl(url)) {
152+
console.log('Invalid URL');
153+
return sendTokenError();
154+
}
124155
const tokenRes = await unirest
125-
.post(`${opts.authServiceUrl}/api/auth/verifyToken`)
156+
.post(url)
126157
.type('json')
127158
.send({ token: splitAuth[1] });
128159
if (tokenRes.ok && tokenRes.body && tokenRes.body.valid) {
@@ -144,7 +175,12 @@ module.exports = opts => {
144175
}
145176

146177
try {
147-
const userRes = await unirest.get(`${opts.userServiceUrl}/api/user/${req.jwtPayload._id}`);
178+
const url = `${opts.userServiceUrl}/api/user/${req.jwtPayload._id}`;
179+
if (!validateUrl(url)) {
180+
console.log('Invalid URL');
181+
return res.status(200).send();
182+
}
183+
const userRes = await unirest.get(url);
148184

149185
if (!userRes || userRes.error || !userRes.ok || !userRes.body || !userRes.body._id) {
150186
console.log('Failed to retrieve user from JWT');

services/ui/angular/src/app/auth/auth.service.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,23 @@ export class AuthService {
6767
return this.loggedInUser;
6868
}
6969

70+
validateUrl(url: string): boolean {
71+
const allowedUrls = [
72+
`${this.endpoint}/login`,
73+
`${this.endpoint}/register`,
74+
`${this.endpoint}/logout`,
75+
`${this.endpoint}/loggedin`
76+
];
77+
return allowedUrls.includes(url);
78+
}
79+
7080
login(username: string, password: string): Observable<boolean> {
7181
this.token = null;
72-
return this.http.post<LoginResponse>(`${this.endpoint}/login`, {username, password})
82+
const url = `${this.endpoint}/login`;
83+
if (!this.validateUrl(url)) {
84+
throw new Error('Invalid URL');
85+
}
86+
return this.http.post<LoginResponse>(url, {username, password})
7387
.pipe(map(({ token, user }) => {
7488
this.token = token;
7589
this.loggedInUser = user;
@@ -78,7 +92,11 @@ export class AuthService {
7892
}
7993

8094
register(registration: Registration): Observable<boolean> {
81-
return this.http.post<LoginResponse>(`${this.endpoint}/register`, registration)
95+
const url = `${this.endpoint}/register`;
96+
if (!this.validateUrl(url)) {
97+
throw new Error('Invalid URL');
98+
}
99+
return this.http.post<LoginResponse>(url, registration)
82100
.pipe(map( ({ token, user }) => {
83101
this.token = token;
84102
this.loggedInUser = user;
@@ -89,7 +107,11 @@ export class AuthService {
89107
logout() {
90108
this.token = null;
91109
this.loggedInUser = null;
92-
this.http.post<void>(`${this.endpoint}/logout`, {});
110+
const url = `${this.endpoint}/logout`;
111+
if (!this.validateUrl(url)) {
112+
throw new Error('Invalid URL');
113+
}
114+
this.http.post<void>(url, {});
93115
this.router.navigate(['/login']);
94116
}
95117
}

0 commit comments

Comments
 (0)