sfdx-hardis
Version:
Swiss-army-knife Toolbox for Salesforce. Allows you to define a complete CD/CD Pipeline. Orchestrate base commands and assist users with interactive wizards
110 lines • 4.78 kB
JavaScript
/* jscpd:ignore-start */
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { Messages } from '@salesforce/core';
import fs from 'fs-extra';
import { glob } from 'glob';
import * as psl from 'psl';
import sortArray from 'sort-array';
import * as url from 'url';
import { catchMatches, generateReports, uxLog } from '../../../../common/utils/index.js';
import { GLOB_IGNORE_PATTERNS } from '../../../../common/utils/projectUtils.js';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('sfdx-hardis', 'org');
export default class RemoteSites extends SfCommand {
static title = 'Audit Remote Sites';
static description = messages.getMessage('auditRemoteSites');
static examples = ['$ sf hardis:project:audit:remotesites'];
// public static args = [{name: 'file'}];
static flags = {
// flag with a value (-n, --name=VALUE)
debug: Flags.boolean({
char: 'd',
default: false,
description: messages.getMessage('debugMode'),
}),
websocket: Flags.string({
description: messages.getMessage('websocket'),
}),
skipauth: Flags.boolean({
description: 'Skip authentication check when a default username is required',
}),
};
// Set this to true if your command requires a project workspace; 'requiresProject' is false by default
static requiresProject = true;
/* jscpd:ignore-end */
matchResults = [];
async run() {
const pattern = '**/*.{remoteSite-meta.xml,remoteSite}';
const catchers = [
{
type: '',
subType: '',
regex: /<url>(.*?)<\/url>/gim,
detail: [
{ name: 'url', regex: /<url>(.*?)<\/url>/gims },
{ name: 'active', regex: /<isActive>(.*?)<\/isActive>/gims },
{
name: 'description',
regex: /<description>(.*?)<\/description>/gimsu,
},
],
},
];
const remoteSiteSettingsFiles = await glob(pattern, { ignore: GLOB_IGNORE_PATTERNS });
this.matchResults = [];
uxLog(this, `Browsing ${remoteSiteSettingsFiles.length} files`);
// Loop in files
for (const file of remoteSiteSettingsFiles) {
const fileText = await fs.readFile(file, 'utf8');
// Loop on criteria to find matches in this file
for (const catcher of catchers) {
const catcherMatchResults = await catchMatches(catcher, file, fileText, this);
this.matchResults.push(...catcherMatchResults);
}
}
// Format result
const result = this.matchResults.map((item) => {
return {
name: item.fileName.replace('.remoteSite-meta.xml', '').replace('.remoteSite', ''),
fileName: item.fileName,
nameSpace: item.fileName.includes('__') ? item.fileName.split('__')[0] : 'Custom',
matches: item.matches,
url: item.detail?.url ? item.detail.url[0] : '',
active: item.detail?.active ? 'yes' : 'no',
description: item.detail?.description ? item.detail.description[0] : '',
protocol: item.detail.url[0].includes('https') ? 'HTTPS' : 'HTTP',
domain: psl.parse(new url.URL(item.detail.url[0]).hostname)?.domain || 'Domain not found',
};
});
// Sort array
const resultSorted = sortArray(result, {
by: ['protocol', 'domain', 'name', 'active', 'description'],
order: ['asc', 'asc', 'asc', 'desc', 'asc'],
});
// Display as table
const resultsLight = JSON.parse(JSON.stringify(resultSorted));
console.table(resultsLight.map((item) => {
delete item.fileName;
delete item.detail;
delete item.matches;
return item;
}));
// Export into csv & excel file
const columns = [
{ key: 'protocol', header: 'Protocol' },
{ key: 'domain', header: 'Domain' },
{ key: 'name', header: 'Name' },
{ key: 'url', header: 'URL' },
{ key: 'active', header: 'Active' },
{ key: 'description', header: 'Description' },
];
const reportFiles = await generateReports(resultSorted, columns, this);
// Return an object to be displayed with --json
return {
outputString: 'Processed callIns and callOuts audit',
result: resultSorted,
reportFiles,
};
}
}
//# sourceMappingURL=remotesites.js.map