Skip to content

Commit abaebc1

Browse files
committed
Add support for intecepting existing Fish shells
1 parent e16e01b commit abaebc1

File tree

3 files changed

+52
-21
lines changed

3 files changed

+52
-21
lines changed

src/interceptors/terminal/existing-terminal-interceptor.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@ import { Mockttp, getLocal } from 'mockttp';
44
import { Interceptor } from '..';
55
import { HtkConfig } from '../../config';
66
import { getTerminalEnvVars } from './terminal-env-overrides';
7-
import { getShellScript } from './terminal-scripts';
7+
import { getBashShellScript, getFishShellScript } from './terminal-scripts';
88

99
interface ServerState {
1010
server: Mockttp;
1111
isActive: boolean;
1212
}
1313

14+
function getShellCommands(port: number) {
15+
return {
16+
'Bash': { command: `eval "$(curl -sS localhost:${port}/setup)"`, description: "Bash-compatible" },
17+
'Fish': { command: `curl -sS localhost:${port}/fish-setup | source`, description: "Fish" }
18+
}
19+
}
20+
1421
export class ExistingTerminalInterceptor implements Interceptor {
1522

1623
private servers: {
@@ -29,40 +36,46 @@ export class ExistingTerminalInterceptor implements Interceptor {
2936
}
3037

3138
isActive(proxyPort: number): boolean {
32-
const serverState = this.servers[proxyPort];
33-
return !!serverState && serverState.isActive;
39+
return this.servers[proxyPort]?.isActive ?? false;
3440
}
3541

36-
async activate(proxyPort: number): Promise<{ port: number }> {
42+
async activate(proxyPort: number): Promise<{ port: number, commands: { [shellName: string]: { command: string, description: string } } }> {
3743
if (this.servers[proxyPort]) {
3844
// Reset isActive, so we wait again for a new request
3945
this.servers[proxyPort].isActive = false;
40-
return { port: this.servers[proxyPort].server.port };
46+
const serverPort = this.servers[proxyPort].server.port;
47+
return {
48+
port: serverPort,
49+
commands: getShellCommands(serverPort)
50+
};
4151
}
4252

4353
const server = getLocal();
4454
await server.start({ startPort: proxyPort + 1, endPort: 65535 });
4555

4656
const envVars = getTerminalEnvVars(proxyPort, this.config.https, 'runtime-inherit', {});
47-
const setupScript = getShellScript(server.urlFor('/success'), envVars);
4857

4958
const serverState = { server, isActive: false };
5059

51-
await server.get('/setup').thenCallback(() => {
52-
return {
53-
status: 200,
54-
headers: { "content-type": "text/x-shellscript" },
55-
body: setupScript
56-
};
57-
});
60+
await server.forGet('/setup').thenReply(200,
61+
getBashShellScript(server.urlFor('/success'), envVars),
62+
{ "content-type": "text/x-shellscript" }
63+
);
64+
await server.forGet('/fish-setup').thenReply(200,
65+
getFishShellScript(server.urlFor('/success'), envVars),
66+
{ "content-type": "application/x-fish" }
67+
);
5868

59-
await server.post('/success').thenCallback(() => {
69+
await server.forPost('/success').thenCallback(() => {
6070
serverState.isActive = true;
6171
return { status: 200 };
6272
});
6373

6474
this.servers[proxyPort] = serverState;
65-
return { port: server.port };
75+
return {
76+
port: server.port,
77+
commands: getShellCommands(server.port)
78+
};
6679
}
6780

6881
async deactivate(proxyPort: number): Promise<void> {

src/interceptors/terminal/terminal-scripts.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ if [ -n "$HTTP_TOOLKIT_ACTIVE" ]
6969
end
7070
${END_CONFIG_SECTION}`;
7171

72-
// A source-able shell script. Should work for everything except fish, sadly.
73-
export const getShellScript = (callbackUrl: string, env: { [name: string]: string }) => `${
72+
// A source-able shell script. Should work for everything sh-compatible, e.g. Bash, Zsh, Ksh etc.
73+
export const getBashShellScript = (callbackUrl: string, env: { [name: string]: string }) => `${
7474
_.map(env, (value, key) => ` export ${key}="${value.replace(/"/g, '\\"')}"`).join('\n')
7575
}
7676
@@ -88,6 +88,24 @@ export const getShellScript = (callbackUrl: string, env: { [name: string]: strin
8888
echo 'HTTP Toolkit interception enabled'
8989
`;
9090

91+
export const getFishShellScript = (callbackUrl: string, env: { [name: string]: string }) => `${
92+
_.map(env, (value, key) => ` set -x ${key} "${value.replace(/"/g, '\\"')}"`).join('\n')
93+
}
94+
95+
if command -v winpty >/dev/null 2>&1
96+
# Work around for winpty's hijacking of certain commands
97+
alias php=php
98+
alias node=node
99+
end
100+
101+
if command -v curl >/dev/null 2>&1
102+
# Let the HTTP Toolkit app know this ran succesfully
103+
curl --noproxy '*' -X POST "${callbackUrl}" >/dev/null 2>&1 &
104+
end
105+
106+
echo 'HTTP Toolkit interception enabled'
107+
`;
108+
91109
// Find the relevant user shell config file, add the above line to it, so that
92110
// shells launched with HTTP_TOOLKIT_ACTIVE set use the interception PATH.
93111
export const editShellStartupScripts = async () => {

test/interceptors/existing-terminal.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@ describe('Existing terminal interceptor', function () {
7777
it("should intercept all popular JS libraries", async function () {
7878
this.timeout(10000);
7979
const { interceptor, server } = await interceptorSetup;
80-
const result = await interceptor.activate(server.port) as { port: number };
80+
const result = await interceptor.activate(server.port) as { port: number, commands: { [shell: string]: { command: string } } };
8181

82-
const mainRule = await server.get(/https?:\/\/example.test\/js\/.*/).thenReply(200);
83-
const stripeRule = await server.get('https://api.stripe.com/v1/customers').thenJson(200, {});
82+
const mainRule = await server.forGet(/https?:\/\/example.test\/js\/.*/).thenReply(200);
83+
const stripeRule = await server.forGet('https://api.stripe.com/v1/customers').thenJson(200, {});
8484

8585
const scriptOutput = await execAsync(`
86-
. <(curl -sS http://localhost:${result.port}/setup);
86+
${result.commands['Bash'].command}
8787
node "${require.resolve('../fixtures/terminal/js-test-script')}"
8888
`, {
8989
shell: '/bin/bash'

0 commit comments

Comments
 (0)