Skip to content

Commit

Permalink
suggestion(server): refactor isWebviewEnvironment
Browse files Browse the repository at this point in the history
  • Loading branch information
Вахрамеев Сергей Сергеевич authored and Вахрамеев Сергей Сергеевич committed Dec 19, 2024
1 parent 577aa2a commit cd7f623
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 54 deletions.
13 changes: 7 additions & 6 deletions src/server/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const THEME_QUERY = 'theme';
export const TITLE = 'title';
export const WEBVIEW_IOS_APP_ID_QUERY = 'applicationId';
export const WEBVIEW_IOS_APP_VERSION_QUERY = 'device_app_version';
export const WEBVIEW_NEXT_PAGE_ID_QUERY = 'nextPageId';
export const NATIVE_PARAMS_COOKIE_NAME = 'app_native_params';
export const APP_VERSION_HEADER_KEY = 'app-version';
export const IOS_APP_ID_QUERY_KEY = 'applicationId';
export const IOS_APP_VERSION_QUERY_KEY = 'device_app_version';
export const NATIVE_PARAMS_COOKIE_KEY = 'app_native_params';
export const NEXT_PAGE_ID_QUERY_KEY = 'nextPageId';
export const THEME_QUERY_KEY = 'theme';
export const TITLE_QUERY_KEY = 'title';
24 changes: 12 additions & 12 deletions src/server/extract-native-params.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
THEME_QUERY,
TITLE,
WEBVIEW_IOS_APP_ID_QUERY,
WEBVIEW_IOS_APP_VERSION_QUERY,
WEBVIEW_NEXT_PAGE_ID_QUERY,
THEME_QUERY_KEY,
TITLE_QUERY_KEY,
IOS_APP_ID_QUERY_KEY,
IOS_APP_VERSION_QUERY_KEY,
NEXT_PAGE_ID_QUERY_KEY,
} from './constants';

import { extractAppVersion } from './utils';

import { extractAndJoinOriginalWebviewParams } from './extract-and-join-original-webview-params';
import { iosAppIdPattern, versionPattern } from './reg-exp-patterns';
import { RequestHeaderType } from "./types";
import { UniversalRequest } from "./types";
import { isWebviewEnvironment } from "./is-webview-environment";
import {NativeParams} from "../shared/types";

Expand All @@ -21,22 +21,22 @@ import {NativeParams} from "../shared/types";
*/

export const extractNativeParams = (
request: RequestHeaderType
request: UniversalRequest
): NativeParams | null => {

if(!isWebviewEnvironment(request)) {
return null;
}

const {
[THEME_QUERY]: themeQuery,
[THEME_QUERY_KEY]: themeQuery,
// При желании через диплинк на вебвью можно передать желаемый заголовок
// По умолчанию нужна именно пустая строка.
[TITLE]: title = '',
[TITLE_QUERY_KEY]: title = '',
// Говорят, этого может и не быть в урле. Формат `com.xxxxxxxxx.app`.
[WEBVIEW_IOS_APP_ID_QUERY]: iosAppIdQuery,
[WEBVIEW_IOS_APP_VERSION_QUERY]: iosAppVersionQuery,
[WEBVIEW_NEXT_PAGE_ID_QUERY]: nextPageId,
[IOS_APP_ID_QUERY_KEY]: iosAppIdQuery,
[IOS_APP_VERSION_QUERY_KEY]: iosAppVersionQuery,
[NEXT_PAGE_ID_QUERY_KEY]: nextPageId,
} = request.query as Record<string, string>;

const originalWebviewParams = extractAndJoinOriginalWebviewParams(
Expand Down
4 changes: 2 additions & 2 deletions src/server/handle-native-params.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { NativeParams } from '../shared/types';
import {extractNativeParams} from "./extract-native-params";
import {setNativeParamsCookie} from "./set-native-params-cookie";
import { RequestHeaderType } from "./types";
import { UniversalRequest } from "./types";

export const handleNativeParams = (
request: RequestHeaderType,
request: UniversalRequest,
setCookie: (cookieKey: string, cookieValue: string) => void
): NativeParams | null => {
const nativeParams = extractNativeParams(request);
Expand Down
1 change: 0 additions & 1 deletion src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ export * from './is-webview-environment';
export * from './extract-native-params';
export * from './set-native-params-cookie';
export * from './handle-native-params';
export * from './types';
37 changes: 13 additions & 24 deletions src/server/is-webview-environment.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
import {
extractAppVersion,
extractUserAgent,
extractNativeParamsFromCookieHeader
} from './utils';
import { RequestHeaderType } from './types';
import { extractAppVersion, extractUserAgent, extractNativeParams } from './utils';
import { UniversalRequest } from './types';
import { versionPattern, webviewUaIOSPattern } from './reg-exp-patterns';

export const isWebviewByUserAgent = (
userAgent: string,
appVersion: string | undefined,
) => {
return (
(appVersion && versionPattern.test(appVersion)) || !!userAgent?.match(webviewUaIOSPattern)
);
};
export const isWebviewEnvironment = (request: UniversalRequest) => {
const nativeParams = extractNativeParams(request);

export const isWebviewByCookies = (nativeParamsFromCookies: Record<string, any> | null) => {
return !!(nativeParamsFromCookies && nativeParamsFromCookies.isWebview)
}
export const isWebviewEnvironment = (
request: RequestHeaderType,
): boolean => {
const userAgent = extractUserAgent(request);
if (nativeParams) {
return true;
}

// `app-version` в заголовках – индикатор вебвью. В iOS есть только в первом запросе от webview
// `app-version` в заголовках – индикатор вебвью. В iOS есть только в первом запросе от webview.
const appVersion = extractAppVersion(request);
const nativeParams = extractNativeParamsFromCookieHeader(request);
const userAgent = extractUserAgent(request);

return isWebviewByCookies(nativeParams) || isWebviewByUserAgent(userAgent, appVersion);
return !!(
(appVersion && versionPattern.test(appVersion)) ||
(userAgent && webviewUaIOSPattern.test(userAgent))
);
};
4 changes: 2 additions & 2 deletions src/server/set-native-params-cookie.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NATIVE_PARAMS_COOKIE_NAME } from "./constants";
import { NATIVE_PARAMS_COOKIE_KEY } from "./constants";
import { NativeParams } from "../shared/types";

export const setNativeParamsCookie = (params: NativeParams, setCookie: (name: string, value: string) => void): void => {
setCookie(NATIVE_PARAMS_COOKIE_NAME, encodeURIComponent(JSON.stringify(params)))
setCookie(NATIVE_PARAMS_COOKIE_KEY, encodeURIComponent(JSON.stringify(params)))
}

4 changes: 2 additions & 2 deletions src/shared/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NATIVE_PARAMS_COOKIE_NAME } from "../server/constants";
import { NATIVE_PARAMS_COOKIE_KEY } from "../server/constants";

/**
* Возвращает объект с `webview-параметрами` из cookies
Expand All @@ -10,7 +10,7 @@ export function extractNativeParamsFromCookies(cookies?: string): Record<string,
}

const cookiesArray = cookies.split('; ');
const cookieString = cookiesArray.find((cookie: string) => cookie.startsWith(`${NATIVE_PARAMS_COOKIE_NAME}=`));
const cookieString = cookiesArray.find((cookie: string) => cookie.startsWith(`${NATIVE_PARAMS_COOKIE_KEY}=`));

if (!cookieString) return null;

Expand Down
2 changes: 1 addition & 1 deletion test/server/extract-native-params.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { extractNativeParams } from '../../src/server/extract-native-params';
import { isWebviewEnvironment, RequestHeaderType } from "../../src/server";
import { isWebviewEnvironment, UniversalRequest } from "../../src/server";
import { IncomingMessage } from "http";
import { Socket } from "net";

Expand Down
8 changes: 4 additions & 4 deletions test/shared/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { extractNativeParamsFromCookies } from '../../src/shared/utils';
import { NATIVE_PARAMS_COOKIE_NAME } from '../../src/server/constants';
import { NATIVE_PARAMS_COOKIE_KEY } from '../../src/server/constants';

describe('extractNativeParamsFromCookies', () => {
it('should return an empty object if cookie header is missing', () => {
Expand All @@ -16,22 +16,22 @@ describe('extractNativeParamsFromCookies', () => {
const nativeParams = { param1: 'value1', param2: 'value2' };
const encodedNativeParams = encodeURIComponent(JSON.stringify(nativeParams));

const result = extractNativeParamsFromCookies(`${NATIVE_PARAMS_COOKIE_NAME}=${encodedNativeParams}`);
const result = extractNativeParamsFromCookies(`${NATIVE_PARAMS_COOKIE_KEY}=${encodedNativeParams}`);
expect(result).toEqual(nativeParams);
});

it('should return null if native params cookie has invalid JSON', () => {
const invalidJsonValue = 'invalid%7Bjson';

const result = extractNativeParamsFromCookies(`${NATIVE_PARAMS_COOKIE_NAME}=${invalidJsonValue}`);
const result = extractNativeParamsFromCookies(`${NATIVE_PARAMS_COOKIE_KEY}=${invalidJsonValue}`);
expect(result).toBeNull();
});

it('should handle multiple cookies and return only native params cookie value', () => {
const nativeParams = { param1: 'value1', param2: 'value2' };
const encodedNativeParams = encodeURIComponent(JSON.stringify(nativeParams));

const result = extractNativeParamsFromCookies(`otherCookie=value; ${NATIVE_PARAMS_COOKIE_NAME}=${encodedNativeParams}; anotherCookie=anotherValue`);
const result = extractNativeParamsFromCookies(`otherCookie=value; ${NATIVE_PARAMS_COOKIE_KEY}=${encodedNativeParams}; anotherCookie=anotherValue`);
expect(result).toEqual(nativeParams);
});
});

0 comments on commit cd7f623

Please sign in to comment.