add option to use ssh keys

Since debian's curl seemed incapable of using ssh keys, base docker images was changed
to archlinux. Instead of installing git-ftp via aur, it is downloaded from git.
This commit is contained in:
Radoslaw Olko 2020-07-23 19:52:24 +02:00
parent 1053c3278e
commit d5aa90bb35
5 changed files with 101 additions and 33 deletions

View File

@ -1,12 +1,12 @@
FROM debian:stable-slim FROM archlinux:20200705
LABEL repository="https://github.com/SamKirkland/FTP-Deploy-Action" LABEL repository="https://github.com/SamKirkland/FTP-Deploy-Action"
LABEL maintainer="Sam Kirkland <FTP-Deploy-Action@samkirkland.com>" LABEL maintainer="Sam Kirkland <FTP-Deploy-Action@samkirkland.com>"
RUN apt-get update RUN pacman -Sy
RUN apt-get install -y git RUN pacman -S --noconfirm git nodejs
RUN apt-get install -y git-ftp ADD https://raw.githubusercontent.com/git-ftp/git-ftp/f6dcf6218c9adae5299900f894309d1c83ebebaf/git-ftp /usr/local/bin/git-ftp
RUN apt-get install -y nodejs RUN chmod +x /usr/local/bin/git-ftp
COPY dist/index.js /deploy.js COPY dist/index.js /deploy.js
RUN chmod +x deploy.js RUN chmod +x deploy.js

View File

@ -10,7 +10,10 @@ inputs:
required: true required: true
ftp-password: ftp-password:
description: 'FTP account password' description: 'FTP account password'
required: true required: false
sftp-key:
description: 'SFTP account key'
required: false
local-dir: local-dir:
description: 'The local folder to copy, defaults to root project folder' description: 'The local folder to copy, defaults to root project folder'
default: ./ default: ./

56
dist/index.js vendored
View File

@ -992,11 +992,15 @@ const fs_1 = __importDefault(__webpack_require__(747));
const util_1 = __webpack_require__(669); const util_1 = __webpack_require__(669);
const writeFileAsync = util_1.promisify(fs_1.default.writeFile); const writeFileAsync = util_1.promisify(fs_1.default.writeFile);
const errorDeploying = "⚠️ Error deploying"; 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() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
const userArguments = getUserArguments(); const userArguments = getUserArguments();
yield configureHost(userArguments); yield configureSSH(userArguments);
yield syncFiles(userArguments); yield syncFiles(userArguments);
console.log("✅ Deploy Complete"); console.log("✅ Deploy Complete");
} }
@ -1007,21 +1011,23 @@ function run() {
}); });
} }
run(); run();
function configureHost(args) { function configureSSH(args) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (args.knownHosts === "") { if (args.knownHosts === "" && args.sftp_key === "") {
return; return;
} }
try { try {
const sshFolder = `${process.env['HOME']}/.ssh`;
yield exec.exec(`mkdir -v -p ${sshFolder}`); yield exec.exec(`mkdir -v -p ${sshFolder}`);
yield exec.exec(`chmod 700 ${sshFolder}`); yield exec.exec(`chmod 700 ${sshFolder}`);
writeFileAsync(`${sshFolder}/known_hosts`, args.knownHosts); writeFileAsync(sshKnownHostsFile, args.knownHosts);
yield exec.exec(`chmod 755 ${sshFolder}/known_hosts`); writeFileAsync(sshKeyFile, args.sftp_key);
console.log("✅ Configured known_hosts"); 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) { catch (error) {
console.error("⚠️ Error configuring known_hosts"); console.error("⚠️ Error configuring .ssh directory");
core.setFailed(error.message); core.setFailed(error.message);
} }
}); });
@ -1030,32 +1036,58 @@ function getUserArguments() {
return { return {
ftp_server: core.getInput("ftp-server", { required: true }), ftp_server: core.getInput("ftp-server", { required: true }),
ftp_username: core.getInput("ftp-username", { 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"), "./"), local_dir: withDefault(core.getInput("local-dir"), "./"),
gitFtpArgs: withDefault(core.getInput("git-ftp-args"), ""), gitFtpArgs: withDefault(core.getInput("git-ftp-args"), ""),
knownHosts: withDefault(core.getInput("known-hosts"), "") knownHosts: withDefault(core.getInput("known-hosts"), "")
}; };
} }
function withDefault(value, defaultValue) { function withDefault(value, defaultValue) {
if (value === "" || value === null || value === undefined) { if (value === "" || value === null || value === undefined || value === "undefined") {
return defaultValue; return defaultValue;
} }
return value; return value;
} }
/**
* Determine auth method from password and key strings
* and return string to be used by git ftp
* (either --paswd=<pass> or --key <path_to_keyfile>)
* 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 * Sync changed files
*/ */
function syncFiles(args) { function syncFiles(args) {
return __awaiter(this, void 0, void 0, function* () { 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 { try {
yield core.group("Uploading files", () => __awaiter(this, void 0, void 0, function* () { 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", "--force",
"--auto-init", "--auto-init",
"--verbose", "--verbose",
`--syncroot=${args.local_dir}`, `--syncroot=${args.local_dir}`,
`--user=${args.ftp_username}`, `--user=${args.ftp_username}`,
`--passwd=${args.ftp_password}`, ...authStr,
args.gitFtpArgs, args.gitFtpArgs,
args.ftp_server args.ftp_server
]); ]);

View File

@ -6,12 +6,17 @@ import { IActionArguments } from './types';
const writeFileAsync = promisify(fs.writeFile); const writeFileAsync = promisify(fs.writeFile);
const errorDeploying = "⚠️ Error deploying"; 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() { async function run() {
try { try {
const userArguments = getUserArguments(); const userArguments = getUserArguments();
await configureHost(userArguments); await configureSSH(userArguments);
await syncFiles(userArguments); await syncFiles(userArguments);
console.log("✅ Deploy Complete"); console.log("✅ Deploy Complete");
@ -24,23 +29,24 @@ async function run() {
run(); run();
async function configureHost(args: IActionArguments): Promise<void> { async function configureSSH(args: IActionArguments): Promise<void> {
if (args.knownHosts === "") { if (args.knownHosts === "" && args.sftp_key === "") {
return; return;
} }
try { try {
const sshFolder = `${process.env['HOME']}/.ssh`;
await exec.exec(`mkdir -v -p ${sshFolder}`); await exec.exec(`mkdir -v -p ${sshFolder}`);
await exec.exec(`chmod 700 ${sshFolder}`); await exec.exec(`chmod 700 ${sshFolder}`);
writeFileAsync(`${sshFolder}/known_hosts`, args.knownHosts); writeFileAsync(sshKnownHostsFile, args.knownHosts);
await exec.exec(`chmod 755 ${sshFolder}/known_hosts`); 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 known_hosts"); console.log("✅ Configured .ssh directory");
} }
catch (error) { catch (error) {
console.error("⚠️ Error configuring known_hosts"); console.error("⚠️ Error configuring .ssh directory");
core.setFailed(error.message); core.setFailed(error.message);
} }
} }
@ -49,7 +55,8 @@ function getUserArguments(): IActionArguments {
return { return {
ftp_server: core.getInput("ftp-server", { required: true }), ftp_server: core.getInput("ftp-server", { required: true }),
ftp_username: core.getInput("ftp-username", { 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"), "./"), local_dir: withDefault(core.getInput("local-dir"), "./"),
gitFtpArgs: withDefault(core.getInput("git-ftp-args"), ""), gitFtpArgs: withDefault(core.getInput("git-ftp-args"), ""),
knownHosts: withDefault(core.getInput("known-hosts"), "") knownHosts: withDefault(core.getInput("known-hosts"), "")
@ -57,28 +64,53 @@ function getUserArguments(): IActionArguments {
} }
function withDefault(value: string, defaultValue: string) { function withDefault(value: string, defaultValue: string) {
if (value === "" || value === null || value === undefined) { if (value === "" || value === null || value === undefined || value === "undefined") {
return defaultValue; return defaultValue;
} }
return value; return value;
} }
/**
* Determine auth method from password and key strings
* and return string to be used by git ftp
* (either --paswd=<pass> or --key <path_to_keyfile>)
* 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 * Sync changed files
*/ */
async function syncFiles(args: IActionArguments) { 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 { try {
await core.group("Uploading files", async () => { await core.group("Uploading files", async () => {
return await exec.exec( return await exec.exec(
"git ftp push", "git-ftp",
[ [
"push",
"--force", "--force",
"--auto-init", "--auto-init",
"--verbose", "--verbose",
`--syncroot=${args.local_dir}`, `--syncroot=${args.local_dir}`,
`--user=${args.ftp_username}`, `--user=${args.ftp_username}`,
`--passwd=${args.ftp_password}`, ...authStr,
args.gitFtpArgs!, args.gitFtpArgs!,
args.ftp_server! args.ftp_server!
] ]

View File

@ -2,6 +2,7 @@ export interface IActionArguments {
ftp_server: string | undefined; ftp_server: string | undefined;
ftp_username: string | undefined; ftp_username: string | undefined;
ftp_password: string | undefined; ftp_password: string | undefined;
sftp_key: string | undefined;
/** @default "." */ /** @default "." */
local_dir: string | undefined; local_dir: string | undefined;