Skip to content

Commit 5fa5691

Browse files
authored
Merge pull request #598 from BlueBubblesApp/zach/fix/ngrok-v5
v1.9.3 - ngrok update fix
2 parents ab69220 + 3daa18f commit 5fa5691

File tree

11 files changed

+181
-28
lines changed

11 files changed

+181
-28
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bluebubbles-server",
3-
"version": "1.9.2",
3+
"version": "1.9.3",
44
"description": "BlueBubbles Server is the app that powers the BlueBubbles app ecosystem",
55
"private": true,
66
"workspaces": [

packages/server/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
APPLEID=
2+
APPLEIDPASS=
3+
TEAMID=

packages/server/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bluebubbles/server",
3-
"version": "1.9.2",
3+
"version": "1.9.3",
44
"main": "./dist/main.js",
55
"license": "Apache-2.0",
66
"author": {
@@ -106,7 +106,7 @@
106106
"macos-version": "^5.2.0",
107107
"mime-types": "^2.1.32",
108108
"minimist": "^1.2.6",
109-
"ngrok": "^4.3.3",
109+
"ngrok": "^5.0.0-beta.2",
110110
"node-forge": "^1.3.1",
111111
"node-mac-contacts": "^1.7.2",
112112
"node-mac-permissions": "^2.3.0",

packages/server/scripts/electron-builder-config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ module.exports = {
5353
"NSAppleEventsUsageDescription": "BlueBubbles needs access to run AppleScripts",
5454
"NSSystemAdministrationUsageDescription": "BlueBubbles needs access to manage your system",
5555
},
56+
"signIgnore": [
57+
"ngrok"
58+
],
5659
"gatekeeperAssess": false,
5760
"minimumSystemVersion": "10.11.0"
5861
},

packages/server/src/server/api/privateApi/modes/dylibPlugins/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@ export abstract class DylibPlugin {
3333
try {
3434
Server().log(`Killing process: ${this.parentApp}`, "debug");
3535
await FileSystem.killProcess(this.parentApp);
36-
} catch (ex) {
37-
Server().log(`Failed to kill parent process (${this.parentApp})! Error: ${ex}`);
36+
} catch (ex: any) {
37+
const errStr = ((typeof ex === 'object') ? ex?.message ?? String(ex) : String(ex)).trim();
38+
if (!errStr.includes('No matching processes belonging to you were found')) {
39+
Server().log(`Failed to kill parent process (${this.parentApp})! Error: ${errStr}`, 'debug');
40+
}
3841
}
3942
}
4043

packages/server/src/server/services/proxyServices/ngrokService/index.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export class NgrokService extends Proxy {
2424
const ngrokKey = Server().repo.getConfig("ngrok_key") as string;
2525
let ngrokProtocol = (Server().repo.getConfig("ngrok_protocol") as Ngrok.Protocol) ?? "http";
2626

27+
if (isEmpty(ngrokKey)) {
28+
throw new Error('You must provide an Auth Token to use the Ngrok Proxy Service!');
29+
}
30+
2731
const opts: Ngrok.Options = {
2832
port: Server().repo.getConfig("socket_port") ?? 1234,
2933
region: (Server().repo.getConfig("ngrok_region") as Ngrok.Region) ?? "us",
@@ -65,14 +69,12 @@ export class NgrokService extends Proxy {
6569
}
6670
};
6771

68-
// If we have a key, use it
69-
if (ngrokKey !== null && ngrokKey !== undefined) {
70-
opts.authtoken = safeTrim(ngrokKey);
71-
await authtoken({
72-
authtoken: safeTrim(ngrokKey),
73-
binPath: (bPath: string) => bPath.replace("app.asar", "app.asar.unpacked")
74-
});
75-
}
72+
// Apply the Ngrok auth token
73+
opts.authtoken = safeTrim(ngrokKey);
74+
await authtoken({
75+
authtoken: safeTrim(ngrokKey),
76+
binPath: (bPath: string) => bPath.replace("app.asar", "app.asar.unpacked")
77+
});
7678

7779
// If there is no key, force http
7880
if (isEmpty(ngrokKey)) {

packages/ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bluebubbles/ui",
3-
"version": "1.9.2",
3+
"version": "1.9.3",
44
"homepage": "./",
55
"license": "Apache-2.0",
66
"scripts": {

packages/ui/src/app/components/fields/NgrokAuthTokenField.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export const NgrokAuthTokenField = ({ helpText }: NgrokAuthTokenFieldProps): JSX
4747
} else if (theNewNgrokToken.includes(' ')) {
4848
setNgrokTokenError('Invalid Ngrok Auth Token! Please check that you have copied it correctly.');
4949
return;
50+
} else if (theNewNgrokToken.length === 0) {
51+
setNgrokTokenError('An Ngrok Auth Token is required to use the Ngrok proxy service!');
52+
return;
5053
}
5154

5255
dispatch(setConfig({ name: 'ngrok_key', value: theNewNgrokToken }));
@@ -60,7 +63,7 @@ export const NgrokAuthTokenField = ({ helpText }: NgrokAuthTokenFieldProps): JSX
6063

6164
return (
6265
<FormControl isInvalid={hasNgrokTokenError}>
63-
<FormLabel htmlFor='ngrok_key'>Ngrok Auth Token (Highly Recommended)</FormLabel>
66+
<FormLabel htmlFor='ngrok_key'>Ngrok Auth Token (Required)</FormLabel>
6467
<Input
6568
id='password'
6669
type={showNgrokToken ? 'text' : 'password'}

packages/ui/src/app/components/fields/ProxySetupField.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { copyToClipboard } from '../../utils/GenericUtils';
2020
import { ConfirmationItems } from '../../utils/ToastUtils';
2121
import { ConfirmationDialog } from '../modals/ConfirmationDialog';
2222
import { saveLanUrl } from 'app/utils/IpcUtils';
23+
import { NgrokAuthTokenDialog } from '../modals/NgrokAuthTokenDialog';
2324

2425

2526
export interface ProxySetupFieldProps {
@@ -44,11 +45,13 @@ const confirmationActions: ConfirmationItems = {
4445
export const ProxySetupField = ({ helpText, showAddress = true }: ProxySetupFieldProps): JSX.Element => {
4546
const dispatch = useAppDispatch();
4647
const dnsRef = useRef(null);
48+
const ngrokRef = useRef(null);
4749
const alertRef = useRef(null);
4850
const proxyService: string = (useAppSelector(state => state.config.proxy_service) ?? '').toLowerCase().replace(' ', '-');
4951
const address: string = useAppSelector(state => state.config.server_address) ?? '';
5052
const port: number = useAppSelector(state => state.config.socket_port) ?? 1234;
5153
const [dnsModalOpen, setDnsModalOpen] = useBoolean();
54+
const [ngrokModalOpen, setNgrokModalOpen] = useBoolean();
5255
const [requiresConfirmation, confirm] = useState((): string | null => {
5356
return null;
5457
});
@@ -64,14 +67,23 @@ export const ProxySetupField = ({ helpText, showAddress = true }: ProxySetupFiel
6467
value={proxyService}
6568
onChange={(e) => {
6669
if (!e.target.value || e.target.value.length === 0) return;
67-
onSelectChange(e);
70+
71+
let shouldSave = true;
6872
if (e.target.value === 'dynamic-dns') {
73+
shouldSave = false;
6974
setDnsModalOpen.on();
75+
} else if (e.target.value === 'ngrok') {
76+
shouldSave = false;
77+
setNgrokModalOpen.on();
7078
} else if (e.target.value === 'cloudflare') {
7179
confirm('confirmation');
7280
} else if (e.target.value === 'lan-url') {
7381
saveLanUrl();
7482
}
83+
84+
if (shouldSave) {
85+
onSelectChange(e);
86+
}
7587
}}
7688
>
7789
<option value='cloudflare'>Cloudflare (Recommended)</option>
@@ -106,12 +118,25 @@ export const ProxySetupField = ({ helpText, showAddress = true }: ProxySetupFiel
106118

107119
<DynamicDnsDialog
108120
modalRef={dnsRef}
109-
onConfirm={(address) => dispatch(setConfig({ name: 'server_address', value: address }))}
121+
onConfirm={(address) => {
122+
dispatch(setConfig({ name: 'proxy_service', value: 'Dynamic DNS' }));
123+
dispatch(setConfig({ name: 'server_address', value: address }));
124+
}}
110125
isOpen={dnsModalOpen}
111126
port={port as number}
112127
onClose={() => setDnsModalOpen.off()}
113128
/>
114129

130+
<NgrokAuthTokenDialog
131+
modalRef={ngrokRef}
132+
onConfirm={(token) => {
133+
dispatch(setConfig({ name: 'proxy_service', value: 'Ngrok' }));
134+
dispatch(setConfig({ name: 'ngrok_key', value: token }));
135+
}}
136+
isOpen={ngrokModalOpen}
137+
onClose={() => setNgrokModalOpen.off()}
138+
/>
139+
115140
<ConfirmationDialog
116141
title="Notice"
117142
modalRef={alertRef}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import React, { useState } from 'react';
2+
import {
3+
AlertDialog,
4+
AlertDialogOverlay,
5+
AlertDialogBody,
6+
AlertDialogContent,
7+
AlertDialogFooter,
8+
AlertDialogHeader,
9+
Button,
10+
Input,
11+
FormControl,
12+
FormErrorMessage,
13+
FormLabel,
14+
Text
15+
} from '@chakra-ui/react';
16+
import { useAppSelector } from '../../hooks';
17+
import { FocusableElement } from '@chakra-ui/utils';
18+
19+
20+
interface NgrokAuthTokenDialogProps {
21+
onCancel?: () => void;
22+
onConfirm?: (address: string) => void;
23+
isOpen: boolean;
24+
modalRef: React.RefObject<FocusableElement>;
25+
onClose: () => void;
26+
}
27+
28+
export const NgrokAuthTokenDialog = ({
29+
onCancel,
30+
onConfirm,
31+
isOpen,
32+
modalRef,
33+
onClose,
34+
}: NgrokAuthTokenDialogProps): JSX.Element => {
35+
const ngrokToken: string = (useAppSelector(state => state.config.ngrok_key) ?? '');
36+
const [authToken, setAuthToken] = useState(ngrokToken);
37+
const [error, setError] = useState('');
38+
const isInvalid = (error ?? '').length > 0;
39+
40+
return (
41+
<AlertDialog
42+
isOpen={isOpen}
43+
leastDestructiveRef={modalRef}
44+
onClose={() => onClose()}
45+
>
46+
<AlertDialogOverlay>
47+
<AlertDialogContent>
48+
<AlertDialogHeader fontSize='lg' fontWeight='bold'>
49+
Set Your Ngrok Auth Token
50+
</AlertDialogHeader>
51+
52+
<AlertDialogBody>
53+
<Text>In order to use Ngrok, you must create a <i>free</i> account and generate an auth token.</Text>
54+
<br />
55+
<Text>
56+
If you have not done so yet, sign up for an account <u><a href="https://dashboard.ngrok.com/signup" target="_blank" rel="noreferrer">here</a></u>
57+
</Text>
58+
<br />
59+
<Text>
60+
Once you have signed up copy your auth token from your Ngrok dashboard <u><a href="https://dashboard.ngrok.com/get-started/your-authtoken" target="_blank" rel="noreferrer">here</a></u>.
61+
Then paste it in the field below.
62+
</Text>
63+
<br />
64+
<FormControl isInvalid={isInvalid}>
65+
<FormLabel htmlFor='address'>Ngrok Auth Token</FormLabel>
66+
<Input
67+
id='ngrok_key'
68+
type='password'
69+
maxWidth="20em"
70+
value={authToken}
71+
onChange={(e) => {
72+
setError('');
73+
setAuthToken(e.target.value);
74+
}}
75+
/>
76+
{isInvalid ? (
77+
<FormErrorMessage>{error}</FormErrorMessage>
78+
) : null}
79+
</FormControl>
80+
81+
</AlertDialogBody>
82+
83+
<AlertDialogFooter>
84+
<Button
85+
ref={modalRef as React.LegacyRef<HTMLButtonElement> | undefined}
86+
onClick={() => {
87+
if (onCancel) onCancel();
88+
onClose();
89+
}}
90+
>
91+
Cancel
92+
</Button>
93+
<Button
94+
ml={3}
95+
bg='brand.primary'
96+
ref={modalRef as React.LegacyRef<HTMLButtonElement> | undefined}
97+
onClick={() => {
98+
if (authToken.length === 0) {
99+
setError('Please enter an Auth Token!');
100+
return;
101+
}
102+
103+
104+
if (onConfirm) onConfirm(authToken);
105+
onClose();
106+
}}
107+
>
108+
Save
109+
</Button>
110+
</AlertDialogFooter>
111+
</AlertDialogContent>
112+
</AlertDialogOverlay>
113+
</AlertDialog>
114+
);
115+
};

0 commit comments

Comments
 (0)