1
0
Code Issues Pull Requests Actions Packages Projects Releases Wiki Activity GitHub Gitee

224 lines
7.0 KiB
JavaScript

'use strict';
// From https://github.com/openstf/adbkit-apkreader
const BinaryXmlParser = require('./binary');
const INTENT_MAIN = 'android.intent.action.MAIN';
const CATEGORY_LAUNCHER = 'android.intent.category.LAUNCHER';
class ManifestParser {
constructor(buffer, options = {}) {
this.buffer = buffer;
this.xmlParser = new BinaryXmlParser(this.buffer, options);
}
collapseAttributes(element) {
const collapsed = Object.create(null);
for (let attr of Array.from(element.attributes)) {
collapsed[attr.name] = attr.typedValue.value;
}
return collapsed;
}
parseIntents(element, target) {
target.intentFilters = [];
target.metaData = [];
return element.childNodes.forEach(element => {
switch (element.nodeName) {
case 'intent-filter':
{
const intentFilter = this.collapseAttributes(element);
intentFilter.actions = [];
intentFilter.categories = [];
intentFilter.data = [];
element.childNodes.forEach(element => {
switch (element.nodeName) {
case 'action':
intentFilter.actions.push(this.collapseAttributes(element));
break;
case 'category':
intentFilter.categories.push(this.collapseAttributes(element));
break;
case 'data':
intentFilter.data.push(this.collapseAttributes(element));
break;
}
});
target.intentFilters.push(intentFilter);
break;
}
case 'meta-data':
target.metaData.push(this.collapseAttributes(element));
break;
}
});
}
parseApplication(element) {
const app = this.collapseAttributes(element);
app.activities = [];
app.activityAliases = [];
app.launcherActivities = [];
app.services = [];
app.receivers = [];
app.providers = [];
app.usesLibraries = [];
app.metaData = [];
element.childNodes.forEach(element => {
switch (element.nodeName) {
case 'activity':
{
const activity = this.collapseAttributes(element);
this.parseIntents(element, activity);
app.activities.push(activity);
if (this.isLauncherActivity(activity)) {
app.launcherActivities.push(activity);
}
break;
}
case 'activity-alias':
{
const activityAlias = this.collapseAttributes(element);
this.parseIntents(element, activityAlias);
app.activityAliases.push(activityAlias);
if (this.isLauncherActivity(activityAlias)) {
app.launcherActivities.push(activityAlias);
}
break;
}
case 'service':
{
const service = this.collapseAttributes(element);
this.parseIntents(element, service);
app.services.push(service);
break;
}
case 'receiver':
{
const receiver = this.collapseAttributes(element);
this.parseIntents(element, receiver);
app.receivers.push(receiver);
break;
}
case 'provider':
{
const provider = this.collapseAttributes(element);
provider.grantUriPermissions = [];
provider.metaData = [];
provider.pathPermissions = [];
element.childNodes.forEach(element => {
switch (element.nodeName) {
case 'grant-uri-permission':
provider.grantUriPermissions.push(this.collapseAttributes(element));
break;
case 'meta-data':
provider.metaData.push(this.collapseAttributes(element));
break;
case 'path-permission':
provider.pathPermissions.push(this.collapseAttributes(element));
break;
}
});
app.providers.push(provider);
break;
}
case 'uses-library':
app.usesLibraries.push(this.collapseAttributes(element));
break;
case 'meta-data':
app.metaData.push(this.collapseAttributes(element));
break;
}
});
return app;
}
isLauncherActivity(activity) {
return activity.intentFilters.some(function (filter) {
const hasMain = filter.actions.some(action => action.name === INTENT_MAIN);
if (!hasMain) {
return false;
}
return filter.categories.some(category => category.name === CATEGORY_LAUNCHER);
});
}
parse() {
const document = this.xmlParser.parse();
const manifest = this.collapseAttributes(document);
manifest.usesPermissions = [];
manifest.usesPermissionsSDK23 = [];
manifest.permissions = [];
manifest.permissionTrees = [];
manifest.permissionGroups = [];
manifest.instrumentation = null;
manifest.usesSdk = null;
manifest.usesConfiguration = null;
manifest.usesFeatures = [];
manifest.supportsScreens = null;
manifest.compatibleScreens = [];
manifest.supportsGlTextures = [];
manifest.application = Object.create(null);
document.childNodes.forEach(element => {
switch (element.nodeName) {
case 'uses-permission':
manifest.usesPermissions.push(this.collapseAttributes(element));
break;
case 'uses-permission-sdk-23':
manifest.usesPermissionsSDK23.push(this.collapseAttributes(element));
break;
case 'permission':
manifest.permissions.push(this.collapseAttributes(element));
break;
case 'permission-tree':
manifest.permissionTrees.push(this.collapseAttributes(element));
break;
case 'permission-group':
manifest.permissionGroups.push(this.collapseAttributes(element));
break;
case 'instrumentation':
manifest.instrumentation = this.collapseAttributes(element);
break;
case 'uses-sdk':
manifest.usesSdk = this.collapseAttributes(element);
break;
case 'uses-configuration':
manifest.usesConfiguration = this.collapseAttributes(element);
break;
case 'uses-feature':
manifest.usesFeatures.push(this.collapseAttributes(element));
break;
case 'supports-screens':
manifest.supportsScreens = this.collapseAttributes(element);
break;
case 'compatible-screens':
element.childNodes.forEach(screen => {
return manifest.compatibleScreens.push(this.collapseAttributes(screen));
});
break;
case 'supports-gl-texture':
manifest.supportsGlTextures.push(this.collapseAttributes(element));
break;
case 'application':
manifest.application = this.parseApplication(element);
break;
}
});
return manifest;
}
}
module.exports = ManifestParser;