Enabled donates url for iOS

Old iOS versions (without donate menu item support) do not send build number and flavor.
Newer iOS versions send it in the form: 2022.11.21-3-ios.

Signed-off-by: Alexander Borsuk <me@alex.bio>
This commit is contained in:
Alexander Borsuk 2022-11-21 10:35:23 +01:00 committed by Roman Tsisyk
parent 8a4330d582
commit cda02e3a23
4 changed files with 136 additions and 26 deletions

View file

@ -47,8 +47,9 @@ export const SERVER = {
},
};
const DONATE_URL = 'https://organicmaps.app/donate/';
const DONATE_URL_RU = 'https://organicmaps.app/ru/donate/';
// Exported for tests.
export const DONATE_URL = 'https://organicmaps.app/donate/';
export const DONATE_URL_RU = 'https://organicmaps.app/ru/donate/';
// Main entry point.
addEventListener('fetch', (event) => {
@ -119,8 +120,9 @@ export async function handleRequest(request: Request) {
servers: servers,
};
// Disable donates for Google reviewers for all google app versions AFTER this one.
// Disable donates for reviewers for all app versions AFTER this one.
const lastApprovedAndReleasedGoogleAppVersionCode = 221102;
const lastApprovedAndReleasediOSAppVersionCode = 221120;
let donatesEnabled = true;
if (
appVersion.flavor === 'google' &&
@ -128,6 +130,14 @@ export async function handleRequest(request: Request) {
appVersion.code > lastApprovedAndReleasedGoogleAppVersionCode)
) {
donatesEnabled = false;
} else if (appVersion.build === undefined) {
// Disable donates for older iOS versions without donates menu support.
donatesEnabled = false;
} else if (
(appVersion.flavor === 'ios' && (request.cf?.asOrganization || '').toLowerCase().includes('apple')) ||
appVersion.code > lastApprovedAndReleasediOSAppVersionCode
) {
donatesEnabled = false;
}
if (donatesEnabled) {

View file

@ -13,37 +13,46 @@ export function parseDataVersion(strDataVersion: string | null): number | null {
return dataVersion;
}
const VERSION_RE = new RegExp('(\\d{4}).(\\d{1,2}).(\\d{1,2})-(\\d{1,9})(?:-([^-]+))?');
// 2022.11.20 for iOS versions released before November 21 (without donate menu)
// 2022.11.24-4-ios for newer iOS versions (with donate menu)
// 2022.12.24-10-Google for Android
const VERSION_RE = /(\d{4}).(\d{1,2}).(\d{1,2})(?:$|-(\d{1,9})(?:-([^-]+))?)/;
// Returns code like 221224 for both platforms, build and flavor for Android and newer iOS versions.
export function parseAppVersion(
versionName: string | null,
): { code: number; build: number | undefined; flavor: string | undefined } | null {
): { code: number; build?: number; flavor?: string | undefined } | null {
if (!versionName) {
return null;
}
const m = versionName.match(VERSION_RE);
if (m === null || m.length < 6) {
if (m === null || m.length < 4) {
return null;
}
const yyyy = parseInt(m[1]);
const mm = parseInt(m[2]);
const dd = parseInt(m[3]);
const build = Number.isNaN(parseInt(m[4])) ? undefined : parseInt(m[4]);
const flavor = (m[5] !== undefined && m[5].toLowerCase()) || undefined;
if (
Number.isNaN(yyyy) ||
yyyy > 2099 ||
yyyy < 2022 ||
Number.isNaN(mm) ||
mm > 12 ||
mm < 1 ||
Number.isNaN(dd) ||
dd > 31 ||
dd < 1
) {
if (Number.isNaN(yyyy) || yyyy > 2099 || yyyy < 2022) {
return null;
}
const mm = parseInt(m[2]);
if (Number.isNaN(mm) || mm > 12 || mm < 1) {
return null;
}
const dd = parseInt(m[3]);
if (Number.isNaN(dd) || dd > 31 || dd < 1) {
return null;
}
const code = parseInt(String(yyyy % 100) + String(mm).padStart(2, '0') + String(dd).padStart(2, '0'));
// Older iOS versions without donate button.
if (m[4] === undefined) {
return { code: code };
}
const buildNumber = parseInt(m[4]);
const build = Number.isNaN(buildNumber) ? 0 : buildNumber;
// 'ios' for iOS devices.
const flavor = (m[5] !== undefined && m[5].toLowerCase()) || undefined;
return {
code: code,
flavor: flavor,

View file

@ -1,17 +1,19 @@
import { describe, expect, test } from '@jest/globals';
import { handleRequest, SERVER } from '../src/index';
import { handleRequest, SERVER, DONATE_URL, DONATE_URL_RU } from '../src/index';
const URL = 'https://worker/servers';
const LAST_DATA_VERSION = SERVER.planet.dataVersions[SERVER.planet.dataVersions.length - 1];
describe('old versions', () => {
test('no dataVersion', async () => {
// Note: CF lowercases all headers.
describe('X-OM-DataVersion', () => {
test('no X-OM-DataVersion', async () => {
const req = new Request(URL);
const result = await handleRequest(req);
expect(result.status).toBe(200);
expect(JSON.parse(await result.text())).toEqual([SERVER.backblaze.url]);
});
test('has dataVersion', async () => {
test('has X-OM-DataVersion', async () => {
const server = SERVER.fi1;
let req = new Request(URL, {
headers: {
@ -22,7 +24,8 @@ describe('old versions', () => {
expect(result.status).toBe(200);
expect(JSON.parse(await result.text())).toContain(server.url);
});
test('default routing to planet', async () => {
test('Default routing to planet', async () => {
let req = new Request(URL, {
headers: {
'X-OM-DataVersion': '210000', // this version doesn't exist on servers
@ -33,3 +36,75 @@ describe('old versions', () => {
expect(JSON.parse(await result.text())).toEqual([SERVER.planet.url]);
});
});
describe('X-OM-AppVersion DonateUrl', () => {
test('Old versions without X-OM-AppVersion and old metaserver JSON format', async () => {
const req = new Request(URL);
const response = await handleRequest(req);
expect(response.status).toBe(200);
expect(JSON.parse(await response.text())).toEqual([SERVER.backblaze.url]);
});
const server = SERVER.fi1;
test('Newer metaserver JSON format with donates support', async () => {
let req = new Request(URL, {
headers: {
'X-OM-AppVersion': '2022.08.23-1-Google',
'X-OM-DataVersion': String(server.dataVersions[0]),
},
});
const response = await handleRequest(req);
expect(response.status).toBe(200);
const result = JSON.parse(await response.text());
expect(result.servers).toBeDefined();
expect(result.servers.length).toBeGreaterThan(0);
expect(result.servers).toContain(server.url);
expect(result.settings).toBeDefined();
expect(result.settings.DonateUrl).toBeDefined();
expect(result.settings.DonateUrl).toEqual(DONATE_URL);
});
test('Newer metaserver JSON format with donates support', async () => {
let req = new Request(URL, {
headers: {
'X-OM-AppVersion': '2022.08.23-1-Google',
'X-OM-DataVersion': String(server.dataVersions[0]),
},
//@ts-ignore
cf: { country: 'RU' },
});
const response = await handleRequest(req);
expect(response.status).toBe(200);
const result = JSON.parse(await response.text());
expect(result.settings.DonateUrl).toBeDefined();
expect(result.settings.DonateUrl).toEqual(DONATE_URL_RU);
});
test('Older iOS versions with X-OM-AppVersion but without donates', async () => {
let req = new Request(URL, {
headers: {
'X-OM-AppVersion': '2022.11.20',
'X-OM-DataVersion': String(server.dataVersions[0]),
},
});
const response = await handleRequest(req);
expect(response.status).toBe(200);
const result = JSON.parse(await response.text());
expect(result.settings).not.toBeDefined();
});
test('Newer iOS versions with donate menu support', async () => {
let req = new Request(URL, {
headers: {
'X-OM-AppVersion': '2022.11.20-4-ios',
'X-OM-DataVersion': String(server.dataVersions[0]),
},
});
const response = await handleRequest(req);
expect(response.status).toBe(200);
const result = JSON.parse(await response.text());
expect(result.settings.DonateUrl).toBeDefined();
expect(result.settings.DonateUrl).toEqual(DONATE_URL);
});
});

View file

@ -20,6 +20,10 @@ describe('parseDataVersion', () => {
describe('parseAppVersion', () => {
const tests: { [key: string]: object | null } = {
// Older iOS releases without donate menu
'2022.08.01': { code: 220801 },
// Newer iOS releases with donate menu
'2022.11.25-5-ios': { code: 221125, build: 5, flavor: 'ios' },
'2022.08.01-1': { code: 220801, build: 1 },
'2022.08.01-1-Google': { code: 220801, build: 1, flavor: 'google' },
// -debug is ignored
@ -32,8 +36,20 @@ describe('parseAppVersion', () => {
'2022.13.31-1': null,
'2022.01.00-1': null,
'2022.01.32-1': null,
'22.01.31-1': null,
'22.01.31': null,
'22.01.31-3-flavor': null,
'202.01.31-1': null,
'202.01.312-1': null,
'202.01.312': null,
'202.01.31-aa-flavor': null,
'202.01.31-5a-flavor': null,
'202.01.31-a5-flavor': null,
'2022..31-11': null,
'2022..31-11-flavor': null,
'.11.31-11': null,
'.11.31-11-flavor': null,
'.11..31-11-flavor': null,
garbage: null,
'': null,
null: null,