Skip to content

Commit

Permalink
update model and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellacosse committed Mar 6, 2024
1 parent 9856e20 commit 35c8007
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/www/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -599,10 +599,10 @@ export class App {
connectionState: ServerConnectionState.DISCONNECTED,
};

if (server.error) {
if (server.providerErrorResponse) {
serverListItem.message = {
type: 'error',
content: server.error,
content: server.providerErrorResponse.message,
};
}

Expand Down
18 changes: 15 additions & 3 deletions src/www/app/outline_server_repository/access_key_serialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,14 @@ export function staticKeyToShadowsocksSessionConfig(staticKey: string): Shadowso
}
}

function parseShadowsocksSessionConfigJson(maybeJsonText: string): ShadowsocksSessionConfig | null {
const {method, password, server, server_port, prefix} = JSON.parse(maybeJsonText);
function parseShadowsocksSessionConfigJson(
maybeJsonText: string
): ShadowsocksSessionConfig | errors.ProviderErrorResponse | null {
const {method, password, server, server_port, prefix, ...rest} = JSON.parse(maybeJsonText);

if ('code' in rest && 'message' in rest) {
return rest as errors.ProviderErrorResponse;
}

// These are the mandatory keys.
const missingKeys = [];
Expand All @@ -63,7 +69,9 @@ function parseShadowsocksSessionConfigJson(maybeJsonText: string): ShadowsocksSe

// fetches information from a dynamic access key and attempts to parse it
// TODO(daniellacosse): unit tests
export async function fetchShadowsocksSessionConfig(configLocation: URL): Promise<ShadowsocksSessionConfig> {
export async function fetchShadowsocksSessionConfig(
configLocation: URL
): Promise<ShadowsocksSessionConfig | errors.ProviderErrorResponse> {
let response;
try {
response = await fetch(configLocation, {cache: 'no-store', redirect: 'follow'});
Expand All @@ -78,6 +86,10 @@ export async function fetchShadowsocksSessionConfig(configLocation: URL): Promis
return staticKeyToShadowsocksSessionConfig(responseBody);
}

if (responseBody.toLocaleUpperCase().includes('ERROR')) {
return {code: 0, message: responseBody, details: {}};
}

return parseShadowsocksSessionConfigJson(responseBody);
} catch (cause) {
throw new errors.ServerAccessKeyInvalid('Failed to parse VPN information fetched from dynamic access key.', {
Expand Down
11 changes: 10 additions & 1 deletion src/www/app/outline_server_repository/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class OutlineServer implements Server {
private static readonly SUPPORTED_CIPHERS = ['chacha20-ietf-poly1305', 'aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'];

errorMessageId?: string;
providerErrorResponse?: errors.ProviderErrorResponse<{}>;
private sessionConfig?: ShadowsocksSessionConfig;

constructor(
Expand Down Expand Up @@ -96,7 +97,15 @@ export class OutlineServer implements Server {

async connect() {
if (this.type === ServerType.DYNAMIC_CONNECTION) {
this.sessionConfig = await fetchShadowsocksSessionConfig(this.sessionConfigLocation);
const sessionConfigOrError = await fetchShadowsocksSessionConfig(this.sessionConfigLocation);

if ('code' in sessionConfigOrError && 'message' in sessionConfigOrError) {
this.providerErrorResponse = sessionConfigOrError as errors.ProviderErrorResponse;

throw new errors.SessionConfigFetchFailed('Failed to fetch VPN information from dynamic access key.');
}

this.sessionConfig = sessionConfigOrError as ShadowsocksSessionConfig;
}

try {
Expand Down
6 changes: 6 additions & 0 deletions src/www/model/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
import {Server} from './server';
import {CustomError} from '../../infrastructure/custom_error';

export interface ProviderErrorResponse<T extends object = {}> {
code: number;
message: string;
details: T;
}

export class ServerAlreadyAdded extends CustomError {
constructor(public readonly server: Server) {
super();
Expand Down
8 changes: 5 additions & 3 deletions src/www/model/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {ProviderErrorResponse} from './errors';

// TODO: add guidelines for this file

export enum ServerType {
Expand All @@ -34,9 +36,6 @@ export interface Server {
// The name of this server, as given by the user.
name: string;

// Error returned pertaining to the server's status
error?: string;

// The location to pull the session config from on each connection.
sessionConfigLocation?: URL;

Expand All @@ -51,6 +50,9 @@ export interface Server {
// must match one of the localized app message.
errorMessageId?: string;

// Provider error returned pertaining to the server's status
providerErrorResponse?: ProviderErrorResponse;

// Connects to the server, redirecting the device's traffic.
connect(): Promise<void>;

Expand Down

0 comments on commit 35c8007

Please sign in to comment.