diff --git a/README.md b/README.md index f53bbeb..ccde115 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ I recommend you store your `ftp-password` as a secret. | `ftp-password` | Yes | CrazyUniquePassword&%123 | | FTP account password | | `local-dir` | No | deploy/ | ./ | Which local folder to deploy, path should be relative to the root and should include trailing slash. `./` is the root of the project | | `git-ftp-args` | No | See `git-ftp-args` section below | | Custom git-ftp arguments, this field is passed through directly into the git-ftp script | +| `known-hosts` | No | hostname ssh-rsa AAAAB3NzaC1y ... | | The desired contents of your .ssh/known_hosts file. See [known hosts setup](#known-hosts-setup) | #### Advanced options using `git-ftp-args` Custom arguments, this field is passed through directly into the git-ftp script. See [git-ftp's manual](https://github.com/git-ftp/git-ftp/blob/master/man/git-ftp.1.md) for all options. @@ -73,7 +74,6 @@ Below is an incomplete list of commonly used args: | `--insecure` | Don't verify server's certificate | | `--cacert ` | Use as CA certificate store. Useful when a server has a self-signed certificate | - ### Ignore specific files when deploying Add patterns to `.git-ftp-ignore` and all matching file names will be ignored. The patterns are interpreted as shell glob patterns. Here are some glob pattern examples: @@ -183,7 +183,7 @@ jobs: Use the legacy FTP over a secure encrypted connection. -Notes about sftp: +Notes about ftps: - Most hosts don't offer FTPS, it's more common on windows/.net hosts and less common on linux hosting - Most hosts don't have a correct certificate setup for ftp domains, [even my host doesn't do it right](https://ftp.samkirkland.com/). This means you'll likely have to add `--insecure` to `git-ftp-args` @@ -219,6 +219,21 @@ Similar in name to FTP but this protocol is entirely new and requires SSH access - You will need to create a **SSH** user to deploy over SFTP. Normally this is your cpanel or hosting providers username and password - Most web hosts change the default port (21), check with your host for your port number + +##### [Setting up `known-hosts` allows you to remove the `--insecure` argument.](#known-hosts-setup) +**Windows** +In powershell run `ssh-keyscan -p ` and copy the hash output +Example for samkirkland.com `ssh-keyscan -p 7822 samkirkland.com` + + +**Linux, or OSX (using homebrew)** +Install the OpenSSH packages and use `ssh-keyscan ` and copy the hash output + +Add the `known-hosts` argument with your hosts hash +Example: `knownhosts: ssh-rsa AAAAB3Nza...H1Q5Spw==` + +*Note: If you receive a `Connection refused` error, you must specify the ssh port to your host* + ```yml on: push name: Publish Website over SFTP @@ -237,7 +252,7 @@ jobs: ftp-server: sftp://ftp.samkirkland.com:7280/ ftp-username: mySFTPUsername ftp-password: ${{ secrets.SFTP_PASSWORD }} - git-ftp-args: --insecure # if your certificate is setup correctly this can be removed + git-ftp-args: --insecure # if your certificate is setup correctly this can be removed (see known-hosts argument) ``` @@ -324,6 +339,9 @@ jobs: * Verify you **don't** have the `--all` git-ftp-args flag set 6. How do I set a upload timeout? * github has a built-in `timeout-minutes` option. Place `timeout-minutes: X` before the `steps:` line. Timeout defaults to 360 minutes. +7. If you are getting a curl error similar to `SSL peer certificate or SSH remote key was not OK` + * **Fix 1:** Whitelist your host via the `known-hosts` configuration option. See [known hosts setup](#known-hosts-setup) in SFTP + * **Fix 2:** Add `--insecure` option ### Debugging locally diff --git a/dist/index.js b/dist/index.js index d40a6ca..c0a4f8d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -659,13 +659,20 @@ var __importStar = (this && this.__importStar) || function (mod) { result["default"] = mod; return result; }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); const core = __importStar(__webpack_require__(470)); const exec = __importStar(__webpack_require__(986)); +const fs_1 = __importDefault(__webpack_require__(747)); +const util_1 = __webpack_require__(669); +const writeFileAsync = util_1.promisify(fs_1.default.writeFile); function run() { return __awaiter(this, void 0, void 0, function* () { const userArguments = getUserArguments(); try { + yield configureHost(userArguments); yield syncFiles(userArguments); console.log("✅ Deploy Complete"); } @@ -676,13 +683,33 @@ function run() { }); } run(); +function configureHost(args) { + return __awaiter(this, void 0, void 0, function* () { + if (args.knownHosts === "") { + 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"); + } + catch (error) { + console.error("⚠️ Error configuring known_hosts"); + throw error; + } + }); +} 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 }), 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"), "") }; } function withDefault(value, defaultValue) { @@ -1001,6 +1028,20 @@ module.exports = require("path"); /***/ }), +/***/ 669: +/***/ (function(module) { + +module.exports = require("util"); + +/***/ }), + +/***/ 747: +/***/ (function(module) { + +module.exports = require("fs"); + +/***/ }), + /***/ 986: /***/ (function(__unusedmodule, exports, __webpack_require__) { diff --git a/src/main.ts b/src/main.ts index fbff22f..ffb3699 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,16 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; +import fs from 'fs'; +import { promisify } from 'util'; import { IActionArguments } from './types'; +const writeFileAsync = promisify(fs.writeFile); + async function run() { const userArguments = getUserArguments(); - + try { + await configureHost(userArguments); await syncFiles(userArguments); console.log("✅ Deploy Complete"); @@ -18,6 +23,26 @@ async function run() { run(); +async function configureHost(args: IActionArguments): Promise { + if (args.knownHosts === "") { + 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"); + } + catch (error) { + console.error("⚠️ Error configuring known_hosts"); + throw error; + } +} function getUserArguments(): IActionArguments { return { @@ -25,7 +50,8 @@ function getUserArguments(): IActionArguments { ftp_username: core.getInput("ftp-username", { required: true }), ftp_password: core.getInput("ftp-password", { required: true }), 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"), "") }; } diff --git a/src/types.ts b/src/types.ts index deb95be..9110ddc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,9 @@ export interface IActionArguments { /** @default "" */ gitFtpArgs: string | undefined; + + /** @default "" */ + knownHosts: string | undefined; } /** @@ -25,4 +28,4 @@ export enum gitFTPExitCode { NotAGitProject = 8, PreFTPPushHookFailed = 9, LocalFileOperationFailed = 10 -} \ No newline at end of file +}