Skip to content

Commit e9ddcea

Browse files
authored
Merge branch 'main' into refactor-cli-to-ts-redone
2 parents 4ce6b3e + 169e0f3 commit e9ddcea

File tree

15 files changed

+191
-107
lines changed

15 files changed

+191
-107
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/git-proxy-cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"git-proxy-cli": "./dist/index.js"
77
},
88
"dependencies": {
9-
"axios": "^1.11.0",
9+
"axios": "^1.12.2",
1010
"yargs": "^17.7.2",
1111
"@finos/git-proxy": "file:../.."
1212
},

src/proxy/processors/push-action/checkAuthorEmails.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ const isEmailAllowed = (email: string): boolean => {
3030
};
3131

3232
const exec = async (req: any, action: Action): Promise<Action> => {
33-
console.log({ req, action });
34-
3533
const step = new Step('checkAuthorEmails');
3634

3735
const uniqueAuthorEmails = [

src/proxy/processors/push-action/checkCommitMessages.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ const isMessageAllowed = (commitMessage: string): boolean => {
5151

5252
// Execute if the repo is approved
5353
const exec = async (req: any, action: Action): Promise<Action> => {
54-
console.log({ req, action });
55-
5654
const step = new Step('checkCommitMessages');
5755

5856
const uniqueCommitMessages = [...new Set(action.commitData?.map((commit) => commit.message))];

src/proxy/processors/push-action/pullRemote.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ const exec = async (req: any, action: Action): Promise<Action> => {
99
const step = new Step('pullRemote');
1010

1111
try {
12-
action.proxyGitPath = `${dir}/${action.timestamp}`;
13-
14-
step.log(`Creating folder ${action.proxyGitPath}`);
12+
action.proxyGitPath = `${dir}/${action.id}`;
1513

1614
if (!fs.existsSync(dir)) {
1715
fs.mkdirSync(dir);
1816
}
1917

2018
if (!fs.existsSync(action.proxyGitPath)) {
19+
step.log(`Creating folder ${action.proxyGitPath}`);
2120
fs.mkdirSync(action.proxyGitPath, 0o755);
2221
}
2322

@@ -33,15 +32,12 @@ const exec = async (req: any, action: Action): Promise<Action> => {
3332
fs,
3433
http: gitHttpClient,
3534
url: action.url,
36-
onAuth: () => ({
37-
username,
38-
password,
39-
}),
4035
dir: `${action.proxyGitPath}/${action.repoName}`,
36+
onAuth: () => ({ username, password }),
37+
singleBranch: true,
38+
depth: 1,
4139
});
4240

43-
console.log('Clone Success: ', action.url);
44-
4541
step.log(`Completed ${cmd}`);
4642
step.setContent(`Completed ${cmd}`);
4743
} catch (e: any) {

src/proxy/routes/index.ts

Lines changed: 72 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,31 @@ import { executeChain } from '../chain';
66
import { processUrlPath, validGitRequest, getAllProxiedHosts } from './helper';
77
import { ProxyOptions } from 'express-http-proxy';
88

9+
enum ActionType {
10+
// eslint-disable-next-line no-unused-vars
11+
ALLOWED = 'Allowed',
12+
// eslint-disable-next-line no-unused-vars
13+
ERROR = 'Error',
14+
// eslint-disable-next-line no-unused-vars
15+
BLOCKED = 'Blocked',
16+
}
17+
918
const logAction = (
1019
url: string,
1120
host: string | null | undefined,
1221
userAgent: string | null | undefined,
13-
errMsg: string | null | undefined,
14-
blockMsg?: string | null | undefined,
22+
type: ActionType,
23+
message?: string,
1524
) => {
16-
let msg = `Action processed: ${!(errMsg || blockMsg) ? 'Allowed' : 'Blocked'}
25+
let msg = `Action processed: ${type}
1726
Request URL: ${url}
1827
Host: ${host}
1928
User-Agent: ${userAgent}`;
20-
if (errMsg) {
21-
msg += `\n Error: ${errMsg}`;
22-
}
23-
if (blockMsg) {
24-
msg += `\n Blocked: ${blockMsg}`;
29+
30+
if (message && type !== ActionType.ALLOWED) {
31+
msg += `\n ${type}: ${message}`;
2532
}
33+
2634
console.log(msg);
2735
};
2836

@@ -34,76 +42,69 @@ const proxyFilter: ProxyOptions['filter'] = async (req, res) => {
3442
urlComponents.gitPath === undefined ||
3543
!validGitRequest(urlComponents.gitPath, req.headers)
3644
) {
37-
logAction(
38-
req.url,
39-
req.headers.host,
40-
req.headers['user-agent'],
41-
'Invalid request received',
42-
null,
43-
);
44-
// return status 200 to ensure that the error message is rendered by the git client
45-
res.status(200).send(handleMessage('Invalid request received'));
45+
const message = 'Invalid request received';
46+
logAction(req.url, req.headers.host, req.headers['user-agent'], ActionType.ERROR, message);
47+
res.status(200).send(handleMessage(message));
4648
return false;
4749
}
4850

4951
const action = await executeChain(req, res);
5052

5153
if (action.error || action.blocked) {
52-
res.set('content-type', 'application/x-git-receive-pack-result');
53-
res.set('expires', 'Fri, 01 Jan 1980 00:00:00 GMT');
54-
res.set('pragma', 'no-cache');
55-
res.set('cache-control', 'no-cache, max-age=0, must-revalidate');
56-
res.set('vary', 'Accept-Encoding');
57-
res.set('x-frame-options', 'DENY');
58-
res.set('connection', 'close');
59-
60-
const packetMessage = handleMessage(action.errorMessage ?? action.blockedMessage ?? '');
61-
62-
logAction(
63-
req.url,
64-
req.headers.host,
65-
req.headers['user-agent'],
66-
action.errorMessage,
67-
action.blockedMessage,
68-
);
69-
// return status 200 to ensure that the error message is rendered by the git client
70-
res.status(200).send(packetMessage);
54+
const message = action.errorMessage ?? action.blockedMessage ?? 'Unknown error';
55+
const type = action.error ? ActionType.ERROR : ActionType.BLOCKED;
56+
57+
logAction(req.url, req.headers.host, req.headers['user-agent'], type, message);
58+
sendErrorResponse(req, res, message);
7159
return false;
7260
}
7361

74-
logAction(
75-
req.url,
76-
req.headers.host,
77-
req.headers['user-agent'],
78-
action.errorMessage,
79-
action.blockedMessage,
80-
);
62+
logAction(req.url, req.headers.host, req.headers['user-agent'], ActionType.ALLOWED);
8163

8264
// this is the only case where we do not respond directly, instead we return true to proxy the request
8365
return true;
8466
} catch (e) {
85-
const packetMessage = handleMessage(`Error occurred in proxy filter function ${e}`);
86-
87-
logAction(
88-
req.url,
89-
req.headers.host,
90-
req.headers['user-agent'],
91-
'Error occurred in proxy filter function: ' + ((e as Error).message ?? e),
92-
null,
93-
);
67+
const message = `Error occurred in proxy filter function ${(e as Error).message ?? e}`;
9468

95-
// return status 200 to ensure that the error message is rendered by the git client
96-
res.status(200).send(packetMessage);
69+
logAction(req.url, req.headers.host, req.headers['user-agent'], ActionType.ERROR, message);
70+
sendErrorResponse(req, res, message);
9771
return false;
9872
}
9973
};
10074

75+
const sendErrorResponse = (req: Request, res: Response, message: string): void => {
76+
// GET requests to /info/refs (used to check refs for many git operations) must use Git protocol error packet format
77+
if (req.method === 'GET' && req.url.includes('/info/refs')) {
78+
res.set('content-type', 'application/x-git-upload-pack-advertisement');
79+
res.status(200).send(handleRefsErrorMessage(message));
80+
return;
81+
}
82+
83+
// Standard git receive-pack response
84+
res.set('content-type', 'application/x-git-receive-pack-result');
85+
res.set('expires', 'Fri, 01 Jan 1980 00:00:00 GMT');
86+
res.set('pragma', 'no-cache');
87+
res.set('cache-control', 'no-cache, max-age=0, must-revalidate');
88+
res.set('vary', 'Accept-Encoding');
89+
res.set('x-frame-options', 'DENY');
90+
res.set('connection', 'close');
91+
92+
res.status(200).send(handleMessage(message));
93+
};
94+
10195
const handleMessage = (message: string): string => {
10296
const body = `\t${message}`;
10397
const len = (6 + Buffer.byteLength(body)).toString(16).padStart(4, '0');
10498
return `${len}\x02${body}\n0000`;
10599
};
106100

101+
const handleRefsErrorMessage = (message: string): string => {
102+
// Git protocol for GET /info/refs error packets: PKT-LINE("ERR" SP explanation-text)
103+
const errorBody = `ERR ${message}`;
104+
const len = (4 + Buffer.byteLength(errorBody)).toString(16).padStart(4, '0');
105+
return `${len}${errorBody}\n0000`;
106+
};
107+
107108
const getRequestPathResolver: (prefix: string) => ProxyOptions['proxyReqPathResolver'] = (
108109
prefix,
109110
) => {
@@ -155,15 +156,10 @@ const teeAndValidate = async (req: Request, res: Response, next: NextFunction) =
155156
(req as any).body = buf;
156157
const verdict = await executeChain(req, res);
157158
if (verdict.error || verdict.blocked) {
158-
const msg = verdict.errorMessage ?? verdict.blockedMessage ?? '';
159+
const message = verdict.errorMessage ?? verdict.blockedMessage ?? 'Unknown error';
160+
const type = verdict.error ? ActionType.ERROR : ActionType.BLOCKED;
159161

160-
logAction(
161-
req.url,
162-
req.headers?.host,
163-
req.headers?.['user-agent'],
164-
verdict.errorMessage,
165-
verdict.blockedMessage,
166-
);
162+
logAction(req.url, req.headers?.host, req.headers?.['user-agent'], type, message);
167163

168164
res
169165
.set({
@@ -176,7 +172,7 @@ const teeAndValidate = async (req: Request, res: Response, next: NextFunction) =
176172
connection: 'close',
177173
})
178174
.status(200) // return status 200 to ensure that the error message is rendered by the git client
179-
.send(handleMessage(msg));
175+
.send(handleMessage(message));
180176
return;
181177
}
182178

@@ -216,7 +212,8 @@ const getRouter = async () => {
216212
proxyReqOptDecorator: proxyReqOptDecorator,
217213
proxyReqBodyDecorator: proxyReqBodyDecorator,
218214
proxyErrorHandler: proxyErrorHandler,
219-
}),
215+
stream: true,
216+
} as any),
220217
);
221218
});
222219

@@ -229,7 +226,8 @@ const getRouter = async () => {
229226
proxyReqOptDecorator: proxyReqOptDecorator,
230227
proxyReqBodyDecorator: proxyReqBodyDecorator,
231228
proxyErrorHandler: proxyErrorHandler,
232-
});
229+
stream: true,
230+
} as any);
233231

234232
console.log('proxy keys registered: ', JSON.stringify(proxyKeys));
235233

@@ -259,4 +257,12 @@ const getRouter = async () => {
259257
return router;
260258
};
261259

262-
export { proxyFilter, getRouter, handleMessage, isPackPost, teeAndValidate, validGitRequest };
260+
export {
261+
proxyFilter,
262+
getRouter,
263+
handleMessage,
264+
handleRefsErrorMessage,
265+
isPackPost,
266+
teeAndValidate,
267+
validGitRequest,
268+
};

src/service/routes/push.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ router.post('/:id/reject', async (req, res) => {
7878
});
7979

8080
router.post('/:id/authorise', async (req, res) => {
81-
console.log({ req });
82-
8381
const questions = req.body.params?.attestation;
8482
console.log({ questions });
8583

src/ui/apiBase.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const stripTrailingSlashes = (s: string) => s.replace(/\/+$/, '');
2+
3+
/**
4+
* The base URL for API requests.
5+
*
6+
* Uses the `VITE_API_URI` environment variable if set, otherwise defaults to the current origin.
7+
* @return {string} The base URL to use for API requests.
8+
*/
9+
export const API_BASE = process.env.VITE_API_URI
10+
? stripTrailingSlashes(process.env.VITE_API_URI)
11+
: '';

src/ui/components/Navbars/DashboardNavbarLinks.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import axios from 'axios';
1818
import { getAxiosConfig } from '../../services/auth';
1919
import { UserData } from '../../../types/models';
2020

21+
import { API_BASE } from '../../apiBase';
22+
2123
const useStyles = makeStyles(styles);
2224

2325
const DashboardNavbarLinks: React.FC = () => {
@@ -51,11 +53,7 @@ const DashboardNavbarLinks: React.FC = () => {
5153

5254
const logout = async () => {
5355
try {
54-
const { data } = await axios.post(
55-
`${process.env.VITE_API_URI || 'http://localhost:3000'}/api/auth/logout`,
56-
{},
57-
getAxiosConfig(),
58-
);
56+
const { data } = await axios.post(`${API_BASE}/api/auth/logout`, {}, getAxiosConfig());
5957

6058
if (!data.isAuth && !data.user) {
6159
setAuth(false);

src/ui/services/user.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import axios, { AxiosError, AxiosResponse } from 'axios';
22
import { getAxiosConfig, processAuthError } from './auth';
33
import { UserData } from '../../types/models';
44

5-
type SetStateCallback<T> = (value: T | ((prevValue: T) => T)) => void;
5+
import { API_BASE } from '../apiBase';
66

7-
const baseUrl = process.env.VITE_API_URI || location.origin;
7+
type SetStateCallback<T> = (value: T | ((prevValue: T) => T)) => void;
88

99
const getUser = async (
1010
setIsLoading?: SetStateCallback<boolean>,
@@ -13,9 +13,9 @@ const getUser = async (
1313
setIsError?: SetStateCallback<boolean>,
1414
id: string | null = null,
1515
): Promise<void> => {
16-
let url = `${baseUrl}/api/auth/profile`;
16+
let url = `${API_BASE}/api/auth/profile`;
1717
if (id) {
18-
url = `${baseUrl}/api/v1/user/${id}`;
18+
url = `${API_BASE}/api/v1/user/${id}`;
1919
}
2020
console.log(url);
2121

@@ -43,7 +43,7 @@ const getUsers = async (
4343
setErrorMessage: SetStateCallback<string>,
4444
query: Record<string, string> = {},
4545
): Promise<void> => {
46-
const url = new URL(`${baseUrl}/api/v1/user`);
46+
const url = new URL(`${API_BASE}/api/v1/user`);
4747
url.search = new URLSearchParams(query).toString();
4848

4949
setIsLoading(true);
@@ -70,7 +70,7 @@ const getUsers = async (
7070

7171
const updateUser = async (data: UserData): Promise<void> => {
7272
console.log(data);
73-
const url = new URL(`${baseUrl}/api/auth/gitAccount`);
73+
const url = new URL(`${API_BASE}/api/auth/gitAccount`);
7474

7575
try {
7676
await axios.post(url.toString(), data, getAxiosConfig());
@@ -89,7 +89,7 @@ const getUserLoggedIn = async (
8989
setIsError: SetStateCallback<boolean>,
9090
setAuth: SetStateCallback<boolean>,
9191
): Promise<void> => {
92-
const url = new URL(`${baseUrl}/api/auth/me`);
92+
const url = new URL(`${API_BASE}/api/auth/me`);
9393

9494
try {
9595
const response: AxiosResponse<UserData> = await axios(url.toString(), getAxiosConfig());

0 commit comments

Comments
 (0)