403Webshell
Server IP : 34.87.99.72  /  Your IP : 216.73.217.31
Web Server : Apache/2.4.46 (Unix) OpenSSL/1.1.1n
System : Linux zlock-bitnami-lamp-prod-v2-vm 4.19.0-16-cloud-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64
User : bitnami ( 1000)
PHP Version : 7.4.18
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /opt/bitnami/nami/node_modules/provisioner/lib/platform/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/bitnami/nami/node_modules/provisioner/lib/platform/linux.js
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const base_1 = require("./base");
const nami_wrapper_1 = require("../nami_wrapper");
const fs = require("fs");
const linux_disk_1 = require("./linux_disk");
const linux_user_group_1 = require("./linux_user_group");
const utils_1 = require("../utils");
const cmd_parser_1 = require("cmd-parser");
;
/**
 * Class for all Linux based operating systems
 */
class LinuxPlatform extends base_1.BasePlatform {
    constructor(options) {
        super(options);
        this.systemPackages = [];
        this.systemPackages = [
            "curl", "wget", "zip", "unzip",
            "screen", "haveged",
            "xfsprogs",
            "logrotate" // logrotate recipe
        ];
    }
    /**
     * Information from login.defs
     */
    get loginPackageConfiguration() {
        if (!this._loginPackageConfiguration) {
            const fileContents = {
                UID_MIN: 1000,
                UID_MAX: 60000,
                SYS_UID_MIN: 101,
                GID_MIN: 1000,
                GID_MAX: 60000,
                SYS_GID_MIN: 101,
            };
            if (nami_wrapper_1.file.exists("/etc/login.defs")) {
                let lines = nami_wrapper_1.file.read("/etc/login.defs").split("\n");
                const exp = new RegExp("^\\s*(.*?)\\s+(.*?)\\s*$");
                lines = lines.filter(l => {
                    return l.match(exp) && !l.match(/^\s*#/);
                });
                for (const match of lines.map(l => l.match(exp))) {
                    fileContents[match[1]] = match[2];
                }
            }
            this.logger.trace("loginPackageConfiguration: file is", fileContents);
            if (!fileContents.SYS_UID_MAX) {
                fileContents.SYS_UID_MAX = parseInt(fileContents.UID_MIN) - 1;
            }
            if (!fileContents.SYS_GID_MAX) {
                fileContents.SYS_GID_MAX = parseInt(fileContents.GID_MIN) - 1;
            }
            this._loginPackageConfiguration = {
                uidMin: parseInt(fileContents.UID_MIN),
                uidMax: parseInt(fileContents.UID_MAX),
                sysUidMin: parseInt(fileContents.SYS_UID_MIN),
                sysUidMax: parseInt(fileContents.SYS_UID_MAX),
                gidMin: parseInt(fileContents.GID_MIN),
                gidMax: parseInt(fileContents.GID_MAX),
                sysGidMin: parseInt(fileContents.SYS_GID_MIN),
                sysGidMax: parseInt(fileContents.SYS_GID_MAX),
                useUserGroups: ((fileContents.USERGROUPS_ENAB || "").toString().toUpperCase() ===
                    "YES")
            };
        }
        return this._loginPackageConfiguration;
    }
    _initPathInfo() {
        const namiRuntimeDirectory = "/opt/bitnami/nami";
        this._pathInfo = {
            pathSeparator: ":",
            namiRuntimeDirectory: namiRuntimeDirectory,
            namiRuntimeBinDirectory: `${namiRuntimeDirectory}/bin`,
            namiCommand: `${namiRuntimeDirectory}/bin/nami`,
            provisionerCommand: `${namiRuntimeDirectory}/bin/provisioner`,
            namiAppPath: "/opt/bitnami",
            namiDataPath: "/bitnami"
        };
        this.platformTags.push("linux");
        // tags for convenience
        if (this.bits.toString() === "64") {
            this.platformTags.push("linux64", "linux-x64", "linux-amd64");
        }
    }
    /**
     * Platform OS and architecture i.e. `linux-x86_64` for 64 bit Linux platform
     */
    get osArch() {
        return (this.bits.toString() === "64") ? "linux-x86_64" : "linux-x86";
    }
    /**
     * Get unique identifier, that will remain same until next machine reboot
     */
    getUniqueBootId() {
        if (!this._uniqueBootId) {
            try {
                this._uniqueBootId = fs.statSync("/proc").ctime.toISOString();
            }
            catch (e) {
                this._uniqueBootId = fs.statSync("/").ctime.toISOString();
                this.logger.debug("Unable to get boot time from /proc; falling back to root fs", e);
            }
        }
        return this._uniqueBootId;
    }
    /**
     * Retrieve information about memory
     */
    getMemoryInfo() {
        let contents = {};
        for (let line of nami_wrapper_1.file.read("/proc/meminfo").split("\n")) {
            let match = line.match(/^\s*(.*):\s+(.*)$/, line);
            if (match) {
                contents[match[1]] = match[2];
            }
        }
        let totalPhysicalKB = parseInt(contents["MemTotal"].replace(/ kB/, ""));
        let totalSwapKB = parseInt(contents["SwapTotal"].replace(/ kB/, ""));
        return {
            totalPhysicalMB: Math.round(totalPhysicalKB / 1024),
            totalSwapMB: Math.round(totalSwapKB / 1024),
        };
    }
    /**
     *  Get the disk free for a path, in MB.
     */
    getFreeDiskSpace(path) {
        let rootPath = "/" + `${path}`.split("/")[1];
        let freeMB = nami_wrapper_1.os.runProgram("df", ["-BM", "--output=avail", rootPath]).split("\n")[1].slice(0, -1);
        return Number(freeMB);
    }
    /**
     * Create a swap file in the swapfile file, of size mb
     * @param swapfile
     * @param mb
     */
    createSwap(swapfile, mb) {
        // prepare swap file
        this.logger.info("Creating swapfile: ", swapfile, " size: ", mb, " MB");
        if (this.getFreeDiskSpace(swapfile) > mb) {
            if (!nami_wrapper_1.file.exists(`${swapfile}.complete`) && !nami_wrapper_1.file.exists(`${swapfile}.lock`)) {
                nami_wrapper_1.file.write(`${swapfile}.lock`, "");
                nami_wrapper_1.os.runProgram("dd", [
                    "if=/dev/zero", `of=${swapfile}`, "bs=1048576", `count=${mb}`
                ]);
                nami_wrapper_1.os.runProgram("mkswap", [swapfile]);
                nami_wrapper_1.file.chmod(swapfile, "600");
                nami_wrapper_1.file.write(`${swapfile}.complete`, "");
                nami_wrapper_1.file.delete(`${swapfile}.lock`);
                this.logger.info("Swapfile created");
            }
            else {
                this.logger.info("Swapfile already exits");
            }
        }
        else {
            this.logger.info("Not enough free space to create swapfile");
        }
    }
    /**
     * Activates the swap on the given swapfile
     * This call is idempotent, it succees if called again after the swap is
     * already setup.
     * It will only throw and exception when the swap could not be activated.
     * @param swapfile
     */
    activateSwap(swapfile) {
        try {
            nami_wrapper_1.os.runProgram("swapon", [swapfile]);
        }
        catch (e) {
            if (!this._swapActive(swapfile)) {
                throw (e);
            }
        }
    }
    _swapActive(swapfile) {
        let swapStats = this._parseSwapOnStat(nami_wrapper_1.os.runProgram("swapon", ["-s"]));
        for (let swapStat of swapStats) {
            if (swapStat.filename === swapfile &&
                swapStat.type === "file" &&
                swapStat.sizeKB > 0) {
                return true;
            }
        }
        return false;
    }
    _parseSwapOnStat(swaponStat) {
        let lines = swaponStat.split("\n");
        const splitterRegex = /[ \t]+/;
        let titles = lines[0].split(splitterRegex);
        this._assertSwapStatTitles(titles);
        let dataLines = lines.slice(1);
        let swapStats = [];
        for (let line of dataLines) {
            let columns = line.split(splitterRegex);
            if (columns.length === 0 || (columns.length === 1 && columns[0] === "")) {
                continue; // skip empty lines, probably last line
            }
            if (columns.length < 3) {
                throw new cmd_parser_1.ParserError(`Too few swap stat data columns(${columns.length}): '${columns}'`);
            }
            let swapEntry = {
                filename: columns[0],
                type: columns[1].toLowerCase(),
                sizeKB: +columns[2]
            };
            swapStats.push(swapEntry);
        }
        return swapStats;
    }
    _assertSwapStatTitles(titles) {
        if (titles.length < 3) {
            throw new cmd_parser_1.ParserError(`Too few swap stat titles (${titles.length}): '${titles}'`);
        }
        if (titles[0].toLowerCase() !== "filename" ||
            titles[1].toLowerCase() !== "type" ||
            titles[2].toLowerCase() !== "size") {
            throw new cmd_parser_1.ParserError(`Expected "filename type size ..." but got ${titles}`);
        }
    }
    _getNetworkInterfaceNamesWithIfconfig() {
        let lines = nami_wrapper_1.os.runProgram("ifconfig", "-a").split("\n");
        const exp = new RegExp("^\\s*([^\\s]*)\\s+Link");
        lines = lines.filter((line) => { return !!(line.match(exp)); });
        lines = lines.map((line) => { return line.match(exp)[1]; });
        return lines;
    }
    _getNetworkInterfaceNamesWithProc() {
        let lines = nami_wrapper_1.file.read("/proc/net/dev").split("\n");
        const exp = new RegExp("^\\s*([^\\s]*):");
        lines = lines.filter((line) => { return !!(line.match(exp)); });
        lines = lines.map((line) => { return line.match(exp)[1]; });
        return lines;
    }
    _getNetworkInterfaceNames() {
        let result;
        try {
            result = this._getNetworkInterfaceNamesWithProc();
        }
        catch (e) {
            this.logger.warn("Unable to read /proc/net/dev", e);
            result = this._getNetworkInterfaceNamesWithIfconfig();
        }
        return result;
    }
    _modifyPortMapping(op, srcPort, destPort) {
        for (const device of this._getNetworkInterfaceNames()) {
            nami_wrapper_1.os.runProgram("iptables", [
                op, "PREROUTING", "-t", "nat", "-i", device, "-p", "tcp",
                "--dport", destPort, "-j", "REDIRECT", "--to-port", srcPort
            ]);
        }
    }
    _deletePortMapping(srcPort, destPort) {
        super._deletePortMapping(srcPort, destPort);
        this._modifyPortMapping("-D", srcPort, destPort);
    }
    _addPortMapping(srcPort, destPort) {
        super._addPortMapping(srcPort, destPort);
        this._modifyPortMapping("-A", srcPort, destPort);
    }
    /**
     * Commands that should be invoked when starting nami to increase common OS limits
     * for child processes - i.e. for Linux this will be passed to bash script
     */
    get increaseLimitsCommands() {
        return [
            // set limit of processes/threads
            "ulimit -u 64000",
            // set limit of open files
            "ulimit -n 100000",
            // set limit of virtual memory
            "ulimit -v unlimited",
            // set limit of file size
            "ulimit -f unlimited",
            // set limit of cpu time
            "ulimit -t unlimited",
            // set limit of memory size
            "ulimit -m unlimited",
            // set limit of locked-in-memory size
            "ulimit -l unlimited"
        ];
    }
    /**
     * Create a system service using init.d or systemd
     * The service will be registered, but not started immediately
     *
     * @param name Name of the service to use
     * @param options Options to use for registering the service
     */
    createSystemService(name, options) {
        const startLevel = options.startLevel || 80;
        const stopLevel = options.stopLevel || (100 - startLevel);
        const startCommand = options.startCommand;
        const stopCommand = options.stopCommand;
        const restartCommand = (options.restartCommand ?
            options.restartCommand :
            `${stopCommand} || exit 1\n    sleep 5\n    ${startCommand}`);
        const ulimitCommands = this.increaseLimitsCommands.length > 0 ?
            this.increaseLimitsCommands.join(" ; ") : "";
        let initScriptMain = `
case "$1" in
  start)
    ${options.increaseLimits ? ulimitCommands : ""}
    ${startCommand}
    exit $?
    ;;
  stop)
    ${stopCommand}
    exit $?
    ;;
  restart|force-reload|reload)
    ${options.increaseLimits ? ulimitCommands : ""}
    ${restartCommand}
    exit $?
    ;;
esac
`;
        this.getInitSystem().installService(name, options.description, initScriptMain, options);
        this.getInitSystem().enableService(name, startLevel, stopLevel);
    }
    /**
     * Get an instance of Disk class for specified device for managing partitions
     * @param name platform-specific device - i.e. `/dev/sda`
     */
    getDiskDevice(device) {
        return new linux_disk_1.LinuxDiskDevice(this, device);
    }
    /**
     * Get name of partition based on name of device and partition number - i.e.
     * `/dev/sda1`
     * @param deviceName name of device - i.e. `/dev/sda`
     * @param partition number of partition - i.e. `1`
     */
    getDiskPartitionName(deviceName, partition) {
        if (deviceName.match(/[0-9]$/)) {
            return `${deviceName}p${partition}`;
        }
        else {
            return `${deviceName}${partition}`;
        }
    }
    /**
     * List names of disk devices (not partitions) available on the system ; such
     * as `["/dev/sda", "/dev/sdb"]`
     */
    getDiskDeviceNames() {
        const suffixTypes = [
            "abcdefgh".split(""),
            "0123456789".split("")
        ];
        let result = [];
        for (const prefix of ["/dev/xvd", "/dev/sd", "/dev/hd", "/dev/nbd", "/dev/vd"]) {
            for (const suffixes of suffixTypes) {
                // check if first disk exists
                if (nami_wrapper_1.file.exists(`${prefix}${suffixes[0]}`)) {
                    for (const suffix of suffixes) {
                        const device = `${prefix}${suffix}`;
                        if (nami_wrapper_1.file.exists(device)) {
                            result.push(device);
                        }
                    }
                    return result;
                }
            }
        }
        return result;
    }
    /**
     * Returns the disk partition that mounts the root directory "/"
     * example: "/dev/sda1"
     */
    getRootDiskPartition() {
        let result = undefined;
        try {
            const mounts = nami_wrapper_1.file.read("/proc/mounts");
            result = mounts.match(new RegExp("^(/dev/\\w*) / ", "m"))[1];
        }
        catch (e) {
            this.logger.warn("Unable to obtain root disk partition", e);
        }
        return result;
    }
    /**
     * Returns the disk device with the partition that mounts the root directory "/"
     * example: "/dev/sda"
     */
    getRootDiskDevice() {
        let result = undefined;
        try {
            const rootDiskPartition = this.getRootDiskPartition();
            if (rootDiskPartition) {
                for (const diskDevice of this.getDiskDeviceNames()) {
                    if (rootDiskPartition.includes(diskDevice)) {
                        result = diskDevice;
                        break;
                    }
                }
            }
        }
        catch (e) {
            this.logger.warn("Unable to obtain root disk device", e);
        }
        return result;
    }
    _renameUserInSudoersFile(map) {
        const sudoersFiles = nami_wrapper_1.file.glob([
            "/etc/sudoers",
            "/etc/sudoers.d/cloud-init",
            "/etc/sudoers.d/90-cloud*"
        ]);
        for (const sudoersFile of sudoersFiles) {
            let contents = nami_wrapper_1.file.read(sudoersFile).split("\n");
            const exp = new RegExp("^(\\s*)([^\\s]+)(\\s.*)$");
            contents = contents.map(line => {
                let match = line.match(exp);
                if (match) {
                    if (map[match[2]]) {
                        line = match[1] + map[match[2]] + match[3];
                    }
                }
                return line;
            });
            nami_wrapper_1.file.write(sudoersFile, contents.join("\n"));
        }
    }
    /*
     * Rename system user, without creating new user in the system
     */
    _renameSystemUser(username, user, options) {
        let args = [];
        if (options.newHome !== user.home) {
            args.push("-d", options.newHome);
        }
        args.push("-l", username);
        args.push(user.username);
        nami_wrapper_1.os.runProgram("usermod", args);
    }
    /*
     * Create new user with same uid/gid and same password, moving new user
     * entry above existing user in passwd file
     */
    _addDuplicatedSystemUser(username, user, options, passwdFileHandler) {
        const shadowFileHandler = linux_user_group_1.getShadowRecords();
        const previousUsername = user.username;
        let dupUser;
        let args = [
            "-d", options.newHome, "-M",
            "-u", options.uid,
            "-g", options.gid,
            "-s", user.shell,
            "-o"
        ];
        if (shadowFileHandler) {
            const shadowRecord = shadowFileHandler.findByName(user.username);
            if (shadowRecord) {
                args.push("-p", shadowRecord.encryptedPassword);
            }
        }
        args.push(username);
        // TODO: make sure secondary groups are also copied
        nami_wrapper_1.os.runProgram("useradd", args);
        if (options.newHome !== user.home) {
            try {
                nami_wrapper_1.os.runProgram("usermod", ["-d", options.newHome, previousUsername]);
            }
            catch (e) {
                this.logger.verbose("Unable to modify user home directory with usermod;", "falling back to modifying /etc/passwd manually", e);
                user = passwdFileHandler.forget().findByName(previousUsername);
                user.home = options.newHome;
                passwdFileHandler.write();
            }
        }
        user = passwdFileHandler.forget().findByName(user.username);
        dupUser = passwdFileHandler.findByName(username);
        // reorder passwd file
        passwdFileHandler.remove(dupUser);
        passwdFileHandler.replace(user, dupUser, user);
        passwdFileHandler.write();
    }
    renameSystemUserAndGroup(username, options) {
        const passwdFileHandler = linux_user_group_1.getPasswdRecords();
        const groupFileHandler = linux_user_group_1.getGroupRecords();
        let previousUsername;
        let result = false;
        let user, group;
        let groupname;
        options = Object.assign({
            uid: this.loginPackageConfiguration.uidMin,
            gid: this.loginPackageConfiguration.gidMin,
            groupname: username,
            keepOriginalUser: true
        }, options || {});
        groupname = options.groupname;
        user = passwdFileHandler.findById(options.uid);
        if (user) {
            previousUsername = user.username;
            group = groupFileHandler.findById(options.gid);
            this.logger.trace("renameSystemUserAndGroup: Retrieved records", {
                user: user, group: group, options: options
            });
            // TODO: improve
            if (previousUsername === username) {
                this.logger.info(`Not renaming user ${username} - already configured as ${options.uid}`);
                return false;
            }
            if (!options.newHome) {
                let homelist = nami_wrapper_1.file.split(user.home);
                homelist.pop();
                homelist.push(username);
                options.newHome = nami_wrapper_1.file.join(homelist);
            }
            if (user.home !== options.newHome) {
                nami_wrapper_1.file.rename(user.home, options.newHome);
            }
            if (options.keepOriginalUser) {
                this._addDuplicatedSystemUser(username, user, options, passwdFileHandler);
            }
            else {
                this._renameSystemUser(username, user, options);
            }
            if (group.groupname === user.username) {
                nami_wrapper_1.os.runProgram("groupmod", ["-n", options.groupname, group.groupname]);
            }
            let sudoersMap = {};
            sudoersMap[previousUsername] = username;
            sudoersMap[`%${previousUsername}`] = options.groupname;
            this._renameUserInSudoersFile(sudoersMap);
            // update cloud-init files
            if (nami_wrapper_1.file.exists("/etc/cloud/cloud.cfg")) {
                nami_wrapper_1.file.substitute("/etc/cloud/cloud.cfg", [
                    { pattern: new RegExp(`user:\\s*${previousUsername}`), value: `user: ${username}` },
                    { pattern: new RegExp(`name:\\s*${previousUsername}`), value: `name: ${username}` },
                    { pattern: new RegExp(`name:\\s(ubuntu|centos|debian)`), value: `name: ${username}` }
                ], {
                    multiline: false
                });
            }
            result = true;
        }
        else {
            this.logger.warn("Unable to rename system user - no system user found");
        }
        return result;
    }
    /**
     * Modify system path by editing system configuration files ; only adding paths is supported
     * @param options path elements to add and/or remove
     */
    modifySystemPath(options) {
        if (options.remove && (options.remove.length > 0)) {
            throw new Error("Removal of items from system path not implemented");
        }
        const additionalPathCode = "\n" +
            `PATH=${this.modifyPathString("", options)}:\$PATH\n` +
            "export PATH\n";
        let systemDirectories = [];
        for (let path of nami_wrapper_1.file.glob([
            "/root/{.bashrc,.profile}",
            "/home/*/{.bashrc,.profile}",
            "/etc/skel/{.bashrc,.profile}",
        ])) {
            if (systemDirectories.indexOf(nami_wrapper_1.file.dirname(path)) < 0) {
                systemDirectories.push(nami_wrapper_1.file.dirname(path));
            }
        }
        ;
        for (let directory of systemDirectories) {
            for (let filename of [".bashrc", ".profile"]) {
                let path = `${directory}/${filename}`;
                let owner = nami_wrapper_1.file.getOwnerAndGroup(directory);
                if (!nami_wrapper_1.file.exists(path)) {
                    nami_wrapper_1.file.write(path, "");
                    nami_wrapper_1.file.chmod(path, "0700");
                    nami_wrapper_1.file.chown(path, owner.uid, owner.gid);
                }
                this.createFileSection(path, {
                    title: "PROVISIONER ADDED ENVIRONMENT SETTINGS",
                    contents: additionalPathCode,
                    addAtBeginning: true
                });
            }
        }
    }
    /**
     * Read secure_path from /etc/sudoers file so provisioner related changes can be applied
     */
    _readPathsFromSudoers(filename) {
        // default paths if not found in /etc/sudoers
        const defaultPaths = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
        let value = defaultPaths;
        const lines = nami_wrapper_1.file.read(filename).split("\n");
        let pattern = new RegExp("^(\\s*Defaults\\s*secure_path=\")(.*)(\"\\s*)");
        for (let line of lines) {
            let result = line.match(pattern);
            if (result) {
                value = result[2];
            }
        }
        return value;
    }
    /**
    * Modify path sudo command provides by editing sudoers file
    * @param options path elements to add and/or remove
     */
    modifySudoersPath(options) {
        let paths = this._readPathsFromSudoers("/etc/sudoers");
        paths = this.modifyPathString(paths, options);
        nami_wrapper_1.file.write("/etc/sudoers.d/99-additional-paths", `Defaults secure_path="${paths}"\n`);
    }
    /**
     * Set contents provisioner specific section of hosts file
     * @param contents Map of IP address to hostname or list of host names
     */
    setHostsFileItems(contents) {
        let sectionInfo = this._fileSectionForHostsFile(contents);
        this.createFileSection("/etc/hosts", sectionInfo);
    }
    _fileSectionForHostsFile(contents) {
        let hostsText = "";
        for (let address of Object.keys(contents || {})) {
            let line = `${address} `;
            if (contents[address] instanceof Array) {
                line += contents[address].join(" ");
            }
            else {
                line += contents[address];
            }
            hostsText += `${line}\n`;
        }
        return {
            title: "PROVISIONER MANAGED HOST RECORDS",
            contents: hostsText
        };
    }
    _getDefaultRouteIPAddress() {
        return __awaiter(this, void 0, void 0, function* () {
            let result;
            let ipAddress;
            try {
                ipAddress = yield utils_1.resolveHostname("myip.bitnami.com", {
                    // timeout of 15 seconds to avoid delays when DNS resolving is not working properly
                    timeout: 15000
                });
            }
            catch (e) {
                this.logger.warn("Unable to resolve myip.bitnami.com IP to address", e);
            }
            // default routable IP address that should not be used and routed explicitly
            ipAddress = ipAddress || "203.0.133.0";
            try {
                result = nami_wrapper_1.os.runProgram("ip", ["route", "get", ipAddress]);
            }
            catch (e) {
                this.logger.trace("Unable to run ip route get", e);
            }
            if (result) {
                let match = result.match(/src\s+([0-9\.]+)(\s|$)/);
                if (match) {
                    result = match[1];
                }
                else {
                    result = undefined;
                }
            }
            return result;
        });
    }
    /**
     * Get all current IP addresses
     */
    getPrivateIPAddresses() {
        return __awaiter(this, void 0, void 0, function* () {
            let ip;
            let output;
            let result = [];
            let localAddresses = [];
            // try to get IP address that is used for routing internet traffic first
            ip = yield this._getDefaultRouteIPAddress();
            if (ip) {
                result.push(ip);
            }
            // iterave over all interfaces
            try {
                output = nami_wrapper_1.os.runProgram("ip", ["addr"]);
            }
            catch (e) {
                this.logger.trace("Unable to run ip addr", e);
            }
            if (output) {
                for (let line of output.split("\n")) {
                    let match = line.match(/\sinet\s+([0-9\.]+)(\/|\s)/);
                    if (match) {
                        ip = match[1];
                        // IP addresses matching docker or localhost should be added at the end of the list
                        if (ip.match(/^(127\.|172\.17\.)/)) {
                            if ((result.indexOf(ip) < 0) && (localAddresses.indexOf(ip) < 0)) {
                                localAddresses.push(ip);
                            }
                        }
                        else {
                            if (result.indexOf(ip) < 0) {
                                result.push(ip);
                            }
                        }
                    }
                }
                result = result.concat(localAddresses);
            }
            return result;
        });
    }
    /**
     * Shutdown or reboot the machine
     */
    shutdown(options) {
        let command;
        options = Object.assign({
            delay: 0,
            type: "poweroff"
        }, options);
        if (options.type === "reboot") {
            command = "reboot";
        }
        else {
            command = "poweroff";
        }
        // perform in the background, using both runInBackground and async shell script
        nami_wrapper_1.os.runProgram("sh", ["-c",
            `(sleep ${options.delay} ; ${command}) >/dev/null 2>/dev/null &`
        ], { runInBackground: true });
    }
    /**
     * Start a system service
     * @param name Name of the service
     */
    startService(name) {
        return __awaiter(this, void 0, void 0, function* () {
            this.getInitSystem().startService(name);
        });
    }
    /**
     * Stop a system service
     * @param name Name of the service
     */
    stopService(name) {
        return __awaiter(this, void 0, void 0, function* () {
            this.getInitSystem().stopService(name);
        });
    }
    /**
     * Restart a system service
     * @param name Name of the service
     */
    restartService(name) {
        return __awaiter(this, void 0, void 0, function* () {
            this.getInitSystem().restartService(name);
        });
    }
    /**
     * Determine additional directories to add to PATH
     */
    getAdditionalSystemPaths() {
        const globPatterns = [
            // find all bin and sbin directories in packages
            `${this.pathInfo.namiAppPath}/{*,*/*,*/*/*}/{bin,sbin}/*`
        ];
        const excludedPaths = [
            // skip adding gonit to path
            `${this.pathInfo.namiAppPath}/gonit`,
            // skip adding stats binaries to path
            `${this.pathInfo.namiAppPath}/stats`,
            // skip adding nami/bin directory as it is explicitly added at the end
            this.pathInfo.namiRuntimeBinDirectory
        ];
        const excludedPattern = /^.*\/node_modules\/.*$/;
        let pathList = [];
        for (let globPattern of globPatterns) {
            for (let filename of nami_wrapper_1.file.glob(globPattern)) {
                if (nami_wrapper_1.file.executable(filename) && !nami_wrapper_1.file.isDirectory(filename)) {
                    let filepathList = nami_wrapper_1.file.split(filename);
                    filepathList.pop();
                    const dirname = nami_wrapper_1.file.join(filepathList);
                    if (excludedPaths.indexOf(dirname) < 0 && pathList.indexOf(dirname) < 0 && !dirname.match(excludedPattern)) {
                        pathList.push(dirname);
                    }
                }
            }
        }
        pathList.push(this.pathInfo.namiRuntimeBinDirectory);
        return pathList;
    }
    reloadFirewall() {
        // Nothing to do here, iptables does not need this
    }
    setPortMappings(portMappings) {
        super.setPortMappings(portMappings);
        this.reloadFirewall();
    }
    /**
    * Mount a device in a given directory. If specified it adds a new entry in
    * the `/etc/fstab` file.
    * @param {MountOptions|MountOptionsShared} mountConfig Options for the mount command
    * @param {Object} [extraOptions]
    * @param {boolean} [extraOptions.addToFstab] Add entry in fstab to mount in every boot
    */
    mount(mountConfig, extraOptions) {
        // set default options
        const options = Object.assign({
            addToFstab: false
        }, typeof extraOptions === "undefined" ? {} : extraOptions);
        // Convert options object to a comma-separated string
        const mountOptionsString = (options) => {
            let optionsString = "";
            for (const key in options) {
                let opt;
                if (typeof options[key] === "boolean") {
                    if (options[key] === true) {
                        opt = key;
                    }
                    else {
                        continue;
                    }
                }
                else {
                    opt = `${key}=${options[key]}`;
                }
                optionsString = optionsString.concat(`${opt},`);
            }
            optionsString = optionsString.slice(0, -1);
            return optionsString;
        };
        // create mountpoint if not created
        nami_wrapper_1.file.mkdir(mountConfig.mountPoint);
        this.logger.debug("Mount configuration", mountConfig);
        nami_wrapper_1.os.runProgram("mount", [
            mountConfig.device,
            mountConfig.mountPoint,
            "--type", mountConfig.type,
            "--options", mountOptionsString(mountConfig.options)
        ]);
        if (options.addToFstab) {
            mountConfig.options.nofail = true; // Avoid VM hang during boot
            const fstabFile = "/etc/fstab";
            if (nami_wrapper_1.file.contains(fstabFile, mountConfig.device) || nami_wrapper_1.file.contains(fstabFile, mountConfig.mountPoint)) {
                const fstabEntryRegExp = new RegExp(`\\s?${mountConfig.device}\\s${mountConfig.mountPoint}.*`);
                if (nami_wrapper_1.file.contains(fstabFile, fstabEntryRegExp)) {
                    // fstab contains an entry with the device and the mount point
                    this.logger.info(`Updating ${mountConfig.device} entry in fstab`);
                    nami_wrapper_1.file.substitute(fstabFile, fstabEntryRegExp, `${mountConfig.device} ${mountConfig.mountPoint} ` +
                        `${mountConfig.type} ${mountOptionsString(mountConfig.options)}`);
                }
                else {
                    // fstab contains an entry with the device or mount point but not for the given mount point
                    throw new Error(`${mountConfig.device}/${mountConfig.mountPoint} entries in ${fstabFile} are not compatible`);
                }
            }
            else {
                this.logger.info(`Adding ${mountConfig.device} to ${fstabFile}`);
                nami_wrapper_1.file.append(fstabFile, `${mountConfig.device} ${mountConfig.mountPoint} ` +
                    `${mountConfig.type} ${mountOptionsString(mountConfig.options)}`);
            }
        }
    }
}
exports.LinuxPlatform = LinuxPlatform;

Youez - 2016 - github.com/yon3zu
LinuXploit