Skip to content

Commit

Permalink
feat(#615): add support for assetlinks.json when compiling app sett…
Browse files Browse the repository at this point in the history
…ings (#616)
  • Loading branch information
m5r authored Apr 29, 2024
1 parent d30ee53 commit f39d22a
Show file tree
Hide file tree
Showing 17 changed files with 309 additions and 3 deletions.
9 changes: 9 additions & 0 deletions src/fn/compile-app-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ const compileAppSettingsForProject = async (projectDir, options) => {
}
appSettings.schedules = scheduleSettings;
}

const assetlinks = readOptionalJson(path.join(projectDir, 'app_settings/assetlinks.json'));
if (assetlinks) {
const validate = validateAppSettings.validateAssetlinks(assetlinks);
if (!validate.valid) {
throw new Error(`Invalid assetlinks: ${validate.error}`);
}
appSettings.assetlinks = assetlinks;
}
} else {
warn(`app_settings.json file should not be edited directly.
Please create a base_settings.json file in app_settings folder and move any manually defined configurations there.`);
Expand Down
17 changes: 17 additions & 0 deletions src/lib/validate-app-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ const ScheduleSchema = joi.array().items(
})
);

const AssetlinksSchema = joi.array().items(
joi.object({
relation: joi.array().items(
joi.string().valid('delegate_permission/common.handle_all_urls').required()
).length(1).required(),
target: joi.object({
namespace: joi.string().valid('android_app').required(),
package_name: joi.string().required(),
sha256_cert_fingerprints: joi.array().items(joi.string().required()).min(1).required(),
}).required(),
}),
).min(1);

module.exports = {
validateFormsSchema: (formsObject) => {
const { error } = FormsSchema.validate(formsObject);
Expand All @@ -72,5 +85,9 @@ module.exports = {
validateScheduleSchema: (scheduleObject) => {
const { error } = ScheduleSchema.validate(scheduleObject);
return error ? { valid: false, error } : { valid: true };
},
validateAssetlinks: (assetlinksObject) => {
const { error } = AssetlinksSchema.validate(assetlinksObject);
return error ? { valid: false, error } : { valid: true };
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"locale": "en",
"locales": [
{
"code": "en",
"name": "English"
},
{
"code": "es",
"name": "Español (Spanish)"
}
],
"kujua-reporting": [
{
"code": "SS",
"reporting_freq": "monthly"
}
],
"assetlinks": [
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "org.medicmobile.webapp.mobile",
"sha256_cert_fingerprints": [
"62:BF:C1:78:24:D8:4D:5C:B4:E1:8B:66:98:EA:14:16:57:6F:A4:E5:96:CD:93:81:B2:65:19:71:A7:80:EA:4D"
]
}
},
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "org.medicmobile.something.else",
"sha256_cert_fingerprints": [
"asdf",
"zxcvbn"
]
}
}
],
"contact_summary": "",
"tasks": {
"rules": "",
"targets": {}
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "org.medicmobile.webapp.mobile"
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"locale": "en",
"locales": [
{
"code": "en",
"name": "English"
},
{
"code": "es",
"name": "Español (Spanish)"
}
],
"kujua-reporting": [
{
"code": "SS",
"reporting_freq": "monthly"
}
]
}
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "org.medicmobile.webapp.mobile",
"sha256_cert_fingerprints": [
"62:BF:C1:78:24:D8:4D:5C:B4:E1:8B:66:98:EA:14:16:57:6F:A4:E5:96:CD:93:81:B2:65:19:71:A7:80:EA:4D"
]
}
},
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "org.medicmobile.something.else",
"sha256_cert_fingerprints": [
"asdf",
"zxcvbn"
]
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"locale": "en",
"locales": [
{
"code": "en",
"name": "English"
},
{
"code": "es",
"name": "Español (Spanish)"
}
],
"kujua-reporting": [
{
"code": "SS",
"reporting_freq": "monthly"
}
]
}
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
13 changes: 11 additions & 2 deletions test/fn/compile-app-settings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const scenarios = [
folder: 'purge/no-export-purge/project',
},
{
description: 'should handle a project with eslint error when --debug flag is present',
description: 'should handle a project with eslint error when --debug flag is present',
folder: 'eslint-error/project',
extraArgs: ['--debug'],
},
Expand All @@ -58,11 +58,15 @@ const scenarios = [
{
description: 'should handle a configuration using the base_settings file',
folder: 'base-settings/project',
},
},
{
description: 'should handle a configuration using the forms.json and schedules.json files',
folder: 'sms-modules/project',
},
{
description: 'should handle a configuration using the assetlinks.json file',
folder: 'android-app-links/project',
},

// REJECTION SCENARIOS
{
Expand Down Expand Up @@ -115,6 +119,11 @@ const scenarios = [
folder: 'missing-eslintrc/project',
error: 'No eslint configuration',
},
{
description: 'should reject a configuration using an invalid assetlinks.json file',
folder: 'android-app-links/invalid-file',
error: 'Invalid assetlinks: ValidationError: "[0].target.sha256_cert_fingerprints" is required',
},
];

describe('compile-app-settings', () => {
Expand Down
144 changes: 143 additions & 1 deletion test/lib/validate-app-settings.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const { expect } = require('chai');
const validateAppSettings = require('../../src/lib/validate-app-settings');

describe('validate-app-settings', () => {

describe('validateFormsSchema', () => {

const isValid = (formsObject) => {
Expand Down Expand Up @@ -158,4 +157,147 @@ describe('validate-app-settings', () => {

});

describe('validateAssetlinks', () => {
const isValid = (assetlinks) => {
const result = validateAppSettings.validateAssetlinks(assetlinks);
expect(result.valid).to.be.true;
};

const isNotValid = (assetlinks, errorMessage) => {
const result = validateAppSettings.validateAssetlinks(assetlinks);
expect(result.valid).to.be.false;
expect(result.error.details.length).to.equal(1);
expect(result.error.details[0].message).to.equal(errorMessage);
};

it('returns true for assetlinks with one entry', () => {
isValid([{
relation: ['delegate_permission/common.handle_all_urls'],
target: {
namespace: 'android_app',
package_name: 'org.medicmobile.webapp.mobile',
sha256_cert_fingerprints: ['long sha256 fingerprint 62:BF:C1:78...']
}
}]);
});

it('returns true for assetlinks with multiple entries', () => {
// for example when associating 1 domain to multiple apks
isValid([
{
relation: ['delegate_permission/common.handle_all_urls'],
target: {
namespace: 'android_app',
package_name: 'org.medicmobile.webapp.mobile',
sha256_cert_fingerprints: ['long sha256 fingerprint 62:BF:C1:78...']
}
},
{
relation: [
'delegate_permission/common.handle_all_urls'
],
target: {
namespace: 'android_app',
package_name: 'org.medicmobile.other.app',
sha256_cert_fingerprints: ['long other sha256 fingerprint 26:FB:1C:87...']
}
},
]);
});

it('returns true for assetlinks with multiple apk fingerprints', () => {
isValid([{
relation: ['delegate_permission/common.handle_all_urls'],
target: {
namespace: 'android_app',
package_name: 'org.medicmobile.webapp.mobile',
sha256_cert_fingerprints: [
'long sha256 fingerprint 62:BF:C1:78...',
'long other sha256 fingerprint 26:FB:1C:87...',
],
}
}]);
});

it('returns false for an empty assetlinks', () => {
isNotValid([], '"value" must contain at least 1 items');
});

it('returns false for assetlinks with constant properties that were changed', () => {
isNotValid(
[{
relation: ['something wrong'],
target: {
namespace: 'android_app',
package_name: 'org.medicmobile.webapp.mobile',
sha256_cert_fingerprints: ['long sha256 fingerprint 62:BF:C1:78...']
}
}],
'"[0].relation[0]" must be [delegate_permission/common.handle_all_urls]',
);

isNotValid(
[{
relation: ['delegate_permission/common.handle_all_urls'],
target: {
namespace: 'something else',
package_name: 'org.medicmobile.webapp.mobile',
sha256_cert_fingerprints: ['long sha256 fingerprint 62:BF:C1:78...']
}
}],
'"[0].target.namespace" must be [android_app]',
);
});

it('returns false for assetlinks with missing properties', () => {
isNotValid(
[{
target: {
namespace: 'android_app',
package_name: 'org.medicmobile.webapp.mobile',
sha256_cert_fingerprints: ['long sha256 fingerprint 62:BF:C1:78...']
}
}],
'"[0].relation" is required',
);

isNotValid(
[{ relation: ['delegate_permission/common.handle_all_urls'] }],
'"[0].target" is required',
);

isNotValid(
[{
relation: ['delegate_permission/common.handle_all_urls'],
target: {
package_name: 'org.medicmobile.webapp.mobile',
sha256_cert_fingerprints: ['long sha256 fingerprint 62:BF:C1:78...']
}
}],
'"[0].target.namespace" is required',
);

isNotValid(
[{
relation: ['delegate_permission/common.handle_all_urls'],
target: {
namespace: 'android_app',
sha256_cert_fingerprints: ['long sha256 fingerprint 62:BF:C1:78...']
}
}],
'"[0].target.package_name" is required',
);

isNotValid(
[{
relation: ['delegate_permission/common.handle_all_urls'],
target: {
namespace: 'android_app',
package_name: 'org.medicmobile.webapp.mobile',
}
}],
'"[0].target.sha256_cert_fingerprints" is required',
);
});
});
});

0 comments on commit f39d22a

Please sign in to comment.