diff --git a/Dockerfile b/Dockerfile index 461c465..57885c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,12 @@ -FROM debian:stable-slim +FROM archlinux:20200705 LABEL repository="https://github.com/SamKirkland/FTP-Deploy-Action" LABEL maintainer="Sam Kirkland " -RUN apt-get update -RUN apt-get install -y git -RUN apt-get install -y git-ftp -RUN apt-get install -y nodejs +RUN pacman -Sy +RUN pacman -S --noconfirm git nodejs +ADD https://raw.githubusercontent.com/git-ftp/git-ftp/f6dcf6218c9adae5299900f894309d1c83ebebaf/git-ftp /usr/local/bin/git-ftp +RUN chmod +x /usr/local/bin/git-ftp COPY dist/index.js /deploy.js RUN chmod +x deploy.js diff --git a/action.yml b/action.yml index 6ca02a8..f9c1eed 100644 --- a/action.yml +++ b/action.yml @@ -10,7 +10,10 @@ inputs: required: true ftp-password: description: 'FTP account password' - required: true + required: false + sftp-key: + description: 'SFTP account key' + required: false local-dir: description: 'The local folder to copy, defaults to root project folder' default: ./ diff --git a/dist/index.js b/dist/index.js index 2a48788..1c7dca1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -992,11 +992,15 @@ const fs_1 = __importDefault(__webpack_require__(747)); const util_1 = __webpack_require__(669); const writeFileAsync = util_1.promisify(fs_1.default.writeFile); const errorDeploying = "⚠️ Error deploying"; +const errorNoAuth = "⚠️ Error: No methods of authentication present! Provide action with either password (ftp_password argument) or ssh key (sftp_key argument)."; +const sshFolder = `${process.env['HOME']}/.ssh`; +const sshKeyFile = `${sshFolder}/id`; +const sshKnownHostsFile = `${sshFolder}/known_hosts`; function run() { return __awaiter(this, void 0, void 0, function* () { try { const userArguments = getUserArguments(); - yield configureHost(userArguments); + yield configureSSH(userArguments); yield syncFiles(userArguments); console.log("✅ Deploy Complete"); } @@ -1007,21 +1011,23 @@ function run() { }); } run(); -function configureHost(args) { +function configureSSH(args) { return __awaiter(this, void 0, void 0, function* () { - if (args.knownHosts === "") { + if (args.knownHosts === "" && args.sftp_key === "") { return; } try { - const sshFolder = `${process.env['HOME']}/.ssh`; yield exec.exec(`mkdir -v -p ${sshFolder}`); yield exec.exec(`chmod 700 ${sshFolder}`); - writeFileAsync(`${sshFolder}/known_hosts`, args.knownHosts); - yield exec.exec(`chmod 755 ${sshFolder}/known_hosts`); - console.log("✅ Configured known_hosts"); + writeFileAsync(sshKnownHostsFile, args.knownHosts); + writeFileAsync(sshKeyFile, args.sftp_key); + yield exec.exec(`bash -c "echo >> ${sshKeyFile}"`); + yield exec.exec(`chmod 600 ${sshKeyFile}`); + yield exec.exec(`chmod 755 ${sshKnownHostsFile}`); + console.log("✅ Configured .ssh directory"); } catch (error) { - console.error("⚠️ Error configuring known_hosts"); + console.error("⚠️ Error configuring .ssh directory"); core.setFailed(error.message); } }); @@ -1030,32 +1036,58 @@ function getUserArguments() { return { ftp_server: core.getInput("ftp-server", { required: true }), ftp_username: core.getInput("ftp-username", { required: true }), - ftp_password: core.getInput("ftp-password", { required: true }), + ftp_password: withDefault(core.getInput("ftp-password"), ""), + sftp_key: withDefault(core.getInput("sftp-key"), ""), local_dir: withDefault(core.getInput("local-dir"), "./"), gitFtpArgs: withDefault(core.getInput("git-ftp-args"), ""), knownHosts: withDefault(core.getInput("known-hosts"), "") }; } function withDefault(value, defaultValue) { - if (value === "" || value === null || value === undefined) { + if (value === "" || value === null || value === undefined || value === "undefined") { return defaultValue; } return value; } +/** + * Determine auth method from password and key strings + * and return string to be used by git ftp + * (either --paswd= or --key ) + * favors key over password + * if none present returns empty array + */ +function getAuthenticationString(password, key) { + if (key !== "") { + return new Array('--key', `${sshKeyFile}`); + } + else if (password !== "") { + return new Array(`--passwd=${password}`); + } + else { + return new Array(); + } +} /** * Sync changed files */ function syncFiles(args) { return __awaiter(this, void 0, void 0, function* () { + const authStr = getAuthenticationString(args.ftp_password, args.sftp_key); + if (authStr.length === 0) { + console.log(errorNoAuth); + core.setFailed(errorNoAuth); + return; + } try { yield core.group("Uploading files", () => __awaiter(this, void 0, void 0, function* () { - return yield exec.exec("git ftp push", [ + return yield exec.exec("git-ftp", [ + "push", "--force", "--auto-init", "--verbose", `--syncroot=${args.local_dir}`, `--user=${args.ftp_username}`, - `--passwd=${args.ftp_password}`, + ...authStr, args.gitFtpArgs, args.ftp_server ]); diff --git a/src/main.ts b/src/main.ts index 3d6ecc9..db9f10c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,12 +6,17 @@ import { IActionArguments } from './types'; const writeFileAsync = promisify(fs.writeFile); const errorDeploying = "⚠️ Error deploying"; +const errorNoAuth = "⚠️ Error: No methods of authentication present! Provide action with either password (ftp_password argument) or ssh key (sftp_key argument)."; + +const sshFolder = `${process.env['HOME']}/.ssh`; +const sshKeyFile = `${sshFolder}/id` +const sshKnownHostsFile = `${sshFolder}/known_hosts` async function run() { try { const userArguments = getUserArguments(); - await configureHost(userArguments); + await configureSSH(userArguments); await syncFiles(userArguments); console.log("✅ Deploy Complete"); @@ -24,23 +29,24 @@ async function run() { run(); -async function configureHost(args: IActionArguments): Promise { - if (args.knownHosts === "") { +async function configureSSH(args: IActionArguments): Promise { + if (args.knownHosts === "" && args.sftp_key === "") { return; } try { - const sshFolder = `${process.env['HOME']}/.ssh`; - await exec.exec(`mkdir -v -p ${sshFolder}`); await exec.exec(`chmod 700 ${sshFolder}`); - writeFileAsync(`${sshFolder}/known_hosts`, args.knownHosts); - await exec.exec(`chmod 755 ${sshFolder}/known_hosts`); - - console.log("✅ Configured known_hosts"); + writeFileAsync(sshKnownHostsFile, args.knownHosts); + writeFileAsync(sshKeyFile, args.sftp_key); + await exec.exec(`bash -c "echo >> ${sshKeyFile}"`); + await exec.exec(`chmod 600 ${sshKeyFile}`); + await exec.exec(`chmod 755 ${sshKnownHostsFile}`); + + console.log("✅ Configured .ssh directory"); } catch (error) { - console.error("⚠️ Error configuring known_hosts"); + console.error("⚠️ Error configuring .ssh directory"); core.setFailed(error.message); } } @@ -49,7 +55,8 @@ function getUserArguments(): IActionArguments { return { ftp_server: core.getInput("ftp-server", { required: true }), ftp_username: core.getInput("ftp-username", { required: true }), - ftp_password: core.getInput("ftp-password", { required: true }), + ftp_password: withDefault(core.getInput("ftp-password"), ""), + sftp_key: withDefault(core.getInput("sftp-key"), ""), local_dir: withDefault(core.getInput("local-dir"), "./"), gitFtpArgs: withDefault(core.getInput("git-ftp-args"), ""), knownHosts: withDefault(core.getInput("known-hosts"), "") @@ -57,28 +64,53 @@ function getUserArguments(): IActionArguments { } function withDefault(value: string, defaultValue: string) { - if (value === "" || value === null || value === undefined) { + if (value === "" || value === null || value === undefined || value === "undefined") { return defaultValue; } return value; } +/** + * Determine auth method from password and key strings + * and return string to be used by git ftp + * (either --paswd= or --key ) + * favors key over password + * if none present returns empty array + */ +function getAuthenticationString(password: string, key: string): string[] { + if (key !== "") { + return new Array('--key', `${sshKeyFile}`); + } else if (password !== "") { + return new Array(`--passwd=${password}`); + } else { + return new Array(); + } +} + /** * Sync changed files */ async function syncFiles(args: IActionArguments) { + const authStr = getAuthenticationString(args.ftp_password!, args.sftp_key!); + if (authStr.length === 0) { + console.log(errorNoAuth); + core.setFailed(errorNoAuth); + return + } + try { await core.group("Uploading files", async () => { return await exec.exec( - "git ftp push", + "git-ftp", [ + "push", "--force", "--auto-init", "--verbose", `--syncroot=${args.local_dir}`, `--user=${args.ftp_username}`, - `--passwd=${args.ftp_password}`, + ...authStr, args.gitFtpArgs!, args.ftp_server! ] @@ -88,4 +120,4 @@ async function syncFiles(args: IActionArguments) { catch (error) { core.setFailed(error.message); } -} \ No newline at end of file +} diff --git a/src/types.ts b/src/types.ts index 1526791..000fc0f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,6 +2,7 @@ export interface IActionArguments { ftp_server: string | undefined; ftp_username: string | undefined; ftp_password: string | undefined; + sftp_key: string | undefined; /** @default "." */ local_dir: string | undefined;