Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6223e756e | ||
|
|
ddccbacf81 | ||
|
|
824c6f1364 | ||
|
|
2386f9980f | ||
|
|
ee3e96e70a | ||
|
|
cbd3dbb31d | ||
|
|
a2cfb8a8f3 | ||
|
|
8b38cd56a1 | ||
|
|
6d672bd70f | ||
|
|
c16ca4bad7 | ||
|
|
158101ca4d | ||
|
|
ac5ec3b3d2 | ||
|
|
6bab396b51 | ||
|
|
0165c9bc33 | ||
|
|
c39c55721f | ||
|
|
38c590851f | ||
|
|
ab9cabd08f | ||
|
|
0f81f6ec9a | ||
|
|
0ca3d5caef | ||
|
|
1dfb44afbe | ||
|
|
ee5cc6e589 | ||
|
|
6ad1a5079e | ||
|
|
d66fb5cf16 | ||
|
|
28e4f64ae8 | ||
|
|
8fb3d4fa9b | ||
|
|
fa6110530f | ||
|
|
7eabea0f1a | ||
|
|
82635217c5 | ||
|
|
0ff24f8744 | ||
|
|
dd13c4b6cc | ||
|
|
639ed9be89 | ||
|
|
ff581e8b44 | ||
|
|
1a8de46fb7 | ||
|
|
ad699b35c0 | ||
|
|
31bc7170f6 | ||
|
|
9cc5d4f9ee | ||
|
|
731c53d97f | ||
|
|
6669833e3d | ||
|
|
ca8d10fddb | ||
|
|
c77487f645 | ||
|
|
88065c4f2a | ||
|
|
6ac5a9240d | ||
|
|
ca0c849738 | ||
|
|
8c44f4b5ea |
35
.github/workflows/ci.yml
vendored
35
.github/workflows/ci.yml
vendored
@@ -13,17 +13,18 @@ jobs:
|
||||
name: ${{ matrix.friendlyName }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node: [12.14.1]
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
node: [14.15.4]
|
||||
os: [macos-latest, windows-latest, ubuntu-18.04]
|
||||
include:
|
||||
- os: macos-latest
|
||||
friendlyName: macOS
|
||||
- os: windows-latest
|
||||
friendlyName: Windows
|
||||
- os: ubuntu-latest
|
||||
- os: ubuntu-18.04
|
||||
friendlyName: Linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -33,19 +34,33 @@ jobs:
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
# This step can be removed as soon as official Windows arm64 builds are published:
|
||||
# https://github.com/nodejs/build/issues/2450#issuecomment-705853342
|
||||
- run: |
|
||||
$NodeVersion = (node --version) -replace '^.'
|
||||
$NodeFallbackVersion = "15.8.0"
|
||||
& .\script\download-node-lib-win-arm64.ps1 $NodeVersion $NodeFallbackVersion
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
name: Install Windows arm64 node.lib
|
||||
|
||||
- name: Install and build
|
||||
run: yarn
|
||||
run: |
|
||||
yarn install
|
||||
yarn build
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
- name: Test
|
||||
run: yarn test
|
||||
shell: bash
|
||||
- name: Prebuild Node x64
|
||||
run: yarn prebuild-node
|
||||
- name: Prebuild Electron x64
|
||||
run: yarn prebuild-electron
|
||||
- name: Prebuild Electron arm64
|
||||
run: yarn prebuild-electron-arm64
|
||||
- name: Prebuild (x64)
|
||||
run: npm run prebuild-napi-x64
|
||||
- name: Prebuild (arm64)
|
||||
run: npm run prebuild-napi-arm64
|
||||
if: ${{ matrix.os != 'ubuntu-18.04' }}
|
||||
- name: Prebuild (Windows x86)
|
||||
run: npm run prebuild-napi-ia32
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
- name: Publish
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
run: yarn upload
|
||||
|
||||
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '45 23 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp', 'javascript', 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
16
README.md
16
README.md
@@ -2,14 +2,14 @@
|
||||
|
||||
A cross-platform no-dependency C executable trampoline which lets GitHub Desktop
|
||||
intercede in order to provide Git with any additional info it needs (like
|
||||
credentials through `GIT_ASKPASS`).
|
||||
credentials through `GIT_ASKPASS` or `SSH_ASKPASS`).
|
||||
|
||||
The intention is to support the same platforms that
|
||||
[Electron supports](https://www.electronjs.org/docs/tutorial/support#supported-platforms).
|
||||
|
||||
## Building
|
||||
|
||||
This project is written as a Node project with the C-portions beign compiled by
|
||||
This project is written as a Node project with the C-portions being compiled by
|
||||
node-gyp. Installing dependencies and building requires Node.js, and yarn. With
|
||||
those prerequisites the initial setup should be as easy as running `yarn` and
|
||||
subsequent builds can be done using `yarn build`. There are some tests available
|
||||
@@ -125,3 +125,15 @@ Thanks to this, with only one generic trampoline that forwards everything via
|
||||
that TCP socket, the implementation for every possible protocol like
|
||||
`GIT_ASKPASS` can live within the GitHub Desktop codebase instead of having
|
||||
multiple trampoline executables.
|
||||
|
||||
## SSH Wrapper
|
||||
|
||||
Along with the trampoline, an SSH wrapper is provided for macOS. The reason for
|
||||
this is macOS before Monterey include an "old" version of OpenSSH that will
|
||||
ignore the `SSH_ASKPASS` variable unless it's unable to write to a tty.
|
||||
|
||||
This SSH wrapper achieves exactly that: just runs whatever `ssh` exists in the
|
||||
path in a way that will use `SSH_ASKPASS` when necessary.
|
||||
|
||||
More recent versions of OpenSSH (starting with 8.3) don't require this wrapper,
|
||||
since they added support for a new `SSH_ASKPASS_REQUIRE` environment variable.
|
||||
|
||||
74
binding.gyp
74
binding.gyp
@@ -2,24 +2,46 @@
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'desktop-trampoline',
|
||||
'defines': [
|
||||
"NAPI_VERSION=<(napi_build_version)",
|
||||
],
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'src/desktop-trampoline.c',
|
||||
'src/socket.c'
|
||||
],
|
||||
'include_dirs': [
|
||||
'<!(node -p "require(\'node-addon-api\').include_dir")',
|
||||
'include'
|
||||
],
|
||||
'xcode_settings': {
|
||||
'OTHER_CFLAGS': [
|
||||
'-Wall',
|
||||
'-Werror'
|
||||
],
|
||||
'-Werror',
|
||||
'-Werror=format-security',
|
||||
'-fPIC',
|
||||
'-D_FORTIFY_SOURCE=1',
|
||||
'-fstack-protector-strong'
|
||||
]
|
||||
},
|
||||
'cflags!': [
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-fPIC',
|
||||
'-pie',
|
||||
'-D_FORTIFY_SOURCE=1',
|
||||
'-fstack-protector-strong',
|
||||
'-Werror=format-security',
|
||||
'-fno-exceptions'
|
||||
],
|
||||
'cflags_cc!': [ '-fno-exceptions' ],
|
||||
'ldflags!': [
|
||||
'-z relro',
|
||||
'-z now'
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
|
||||
},
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'defines': [ 'WINDOWS' ],
|
||||
@@ -29,5 +51,53 @@
|
||||
}]
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'ssh-wrapper',
|
||||
'defines': [
|
||||
"NAPI_VERSION=<(napi_build_version)",
|
||||
],
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'src/ssh-wrapper.c'
|
||||
],
|
||||
'include_dirs': [
|
||||
'<!(node -p "require(\'node-addon-api\').include_dir")',
|
||||
'include'
|
||||
],
|
||||
'xcode_settings': {
|
||||
'OTHER_CFLAGS': [
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-Werror=format-security',
|
||||
'-fPIC',
|
||||
'-D_FORTIFY_SOURCE=1',
|
||||
'-fstack-protector-strong'
|
||||
]
|
||||
},
|
||||
'cflags!': [
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-fPIC',
|
||||
'-pie',
|
||||
'-D_FORTIFY_SOURCE=1',
|
||||
'-fstack-protector-strong',
|
||||
'-Werror=format-security',
|
||||
'-fno-exceptions'
|
||||
],
|
||||
'cflags_cc!': [ '-fno-exceptions' ],
|
||||
'ldflags!': [
|
||||
'-z relro',
|
||||
'-z now'
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
|
||||
},
|
||||
'conditions': [
|
||||
# For now only build it for macOS, since it's not needed on Windows
|
||||
['OS=="win"', {
|
||||
'defines': [ 'WINDOWS' ],
|
||||
}]
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
25
docs/releases.md
Normal file
25
docs/releases.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Releases
|
||||
|
||||
All releases are published using GitHub releases. Anyone with push access to the
|
||||
repository can create a new release.
|
||||
|
||||
### Release Process
|
||||
|
||||
1. Create a branch named `releases/X.Y.Z`, where `X.Y.Z` is the version you want
|
||||
to release.
|
||||
1. Update the `version` field in the `package.json` with the new version you're
|
||||
about to release.
|
||||
1. Open a Pull Request for that branch.
|
||||
1. Once the branch is approved, `git tag vX.Y.Z` the version you wish to
|
||||
publish. **Important:** the version in the tag name must be preceeded by a
|
||||
`v`.
|
||||
1. `git push --follow-tags` to ensure all new commits (and the tag) are pushed
|
||||
to the remote. Pushing the tag will start the release process.
|
||||
1. Wait a few minutes for the build to finish (look for the build in
|
||||
https://github.com/desktop/desktop-trampoline/actions)
|
||||
1. Once the build is complete it will create a new release with all of the
|
||||
assets and suggested release notes.
|
||||
1. Update the changelog to whatever makes sense for this release. It should be
|
||||
focused on user-facing changes.
|
||||
1. Confirm all assets are uploaded for all the supported platforms.
|
||||
1. Merge the Pull Request into `main` and you're done :tada:
|
||||
3
index.d.ts
vendored
3
index.d.ts
vendored
@@ -1,2 +1,5 @@
|
||||
export function getDesktopTrampolinePath(): string
|
||||
export function getDesktopTrampolineFilename(): string
|
||||
|
||||
export function getSSHWrapperPath(): string
|
||||
export function getSSHWrapperFilename(): string
|
||||
|
||||
10
index.js
10
index.js
@@ -15,7 +15,17 @@ function getDesktopTrampolineFilename() {
|
||||
: 'desktop-trampoline'
|
||||
}
|
||||
|
||||
function getSSHWrapperPath() {
|
||||
return Path.join(__dirname, 'build', 'Release', getSSHWrapperFilename())
|
||||
}
|
||||
|
||||
function getSSHWrapperFilename() {
|
||||
return process.platform === 'win32' ? 'ssh-wrapper.exe' : 'ssh-wrapper'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getDesktopTrampolinePath,
|
||||
getDesktopTrampolineFilename,
|
||||
getSSHWrapperPath,
|
||||
getSSHWrapperFilename,
|
||||
}
|
||||
|
||||
33
package.json
33
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "desktop-trampoline",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.8",
|
||||
"main": "index.js",
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@@ -15,10 +15,10 @@
|
||||
"test": "jest",
|
||||
"lint": "prettier -c **/*.js **/*.md",
|
||||
"lint:fix": "prettier --write **/*.js **/*.md",
|
||||
"prebuild-node": "prebuild -t 10.11.0 -t 11.9.0 -t 12.0.0 -t 14.8.0 --strip --include-regex \"desktop-trampoline(\\.exe)?$\"",
|
||||
"prebuild-electron": "prebuild -t 7.0.0 -t 8.0.0 -t 9.0.0 -t 10.0.0 -t 11.0.0 -r electron --strip --include-regex \"desktop-trampoline(\\.exe)?$\"",
|
||||
"prebuild-electron-arm64": "prebuild -t 7.0.0 -t 8.0.0 -t 9.0.0 -t 10.0.0 -t 11.0.0 -r electron -a arm64 --strip --include-regex \"desktop-trampoline(\\.exe)?$\"",
|
||||
"prebuild-all": "yarn prebuild-node && yarn prebuild-electron && yarn prebuild-electron-arm64",
|
||||
"prebuild-napi-x64": "prebuild -t 3 -r napi -a x64 --strip --include-regex \"(desktop-trampoline|ssh-wrapper)(\\.exe)?$\"",
|
||||
"prebuild-napi-ia32": "prebuild -t 3 -r napi -a ia32 --strip --include-regex \"(desktop-trampoline|ssh-wrapper)(\\.exe)?$\"",
|
||||
"prebuild-napi-arm64": "prebuild -t 3 -r napi -a arm64 --strip --include-regex \"(desktop-trampoline|ssh-wrapper)(\\.exe)?$\"",
|
||||
"prebuild-all": "yarn prebuild-napi-x64 && yarn prebuild-napi-ia32 && yarn prebuild-napi-arm64",
|
||||
"upload": "node ./script/upload.js"
|
||||
},
|
||||
"repository": {
|
||||
@@ -29,11 +29,24 @@
|
||||
"url": "https://github.com/desktop/desktop-trampoline/issues"
|
||||
},
|
||||
"homepage": "https://github.com/desktop/desktop-trampoline#readme",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^4.3.0",
|
||||
"prebuild-install": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest": "^26.4.2",
|
||||
"node-gyp": "^7.1.0",
|
||||
"prebuild": "^10.0.1",
|
||||
"prettier": "^2.1.2",
|
||||
"split2": "^3.2.2"
|
||||
"jest": "^27.5.0",
|
||||
"node-gyp": "^8.4.1",
|
||||
"prebuild": "^11.0.3",
|
||||
"prettier": "^2.5.1",
|
||||
"split2": "^4.1.0"
|
||||
},
|
||||
"binary": {
|
||||
"napi_versions": [
|
||||
3
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"runtime": "napi",
|
||||
"target": 3
|
||||
}
|
||||
}
|
||||
|
||||
36
script/download-node-lib-win-arm64.ps1
Normal file
36
script/download-node-lib-win-arm64.ps1
Normal file
@@ -0,0 +1,36 @@
|
||||
# This script can be removed as soon as official Windows arm64 builds are published:
|
||||
# https://github.com/nodejs/build/issues/2450#issuecomment-705853342
|
||||
|
||||
$nodeVersion = $args[0]
|
||||
$fallbackVersion = $args[1]
|
||||
|
||||
If ($null -eq $nodeVersion -Or $null -eq $fallbackVersion) {
|
||||
Write-Error "No NodeJS version given as argument to this file. Run it like download-nodejs-win-arm64.ps1 NODE_VERSION NODE_FALLBACK_VERSION"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$url = "https://unofficial-builds.nodejs.org/download/release/v$nodeVersion/win-arm64/node.lib"
|
||||
$fallbackUrl = "https://unofficial-builds.nodejs.org/download/release/v$fallbackVersion/win-arm64/node.lib"
|
||||
|
||||
# Always write to the $nodeVersion cache folder, even if we're using the fallbackVersion
|
||||
$cacheFolder = "$env:TEMP\prebuild\napi\$nodeVersion\arm64"
|
||||
|
||||
If (!(Test-Path $cacheFolder)) {
|
||||
New-Item -ItemType Directory -Force -Path $cacheFolder
|
||||
}
|
||||
|
||||
$output = "$cacheFolder\node.lib"
|
||||
$start_time = Get-Date
|
||||
|
||||
Try {
|
||||
Invoke-WebRequest -Uri $url -OutFile $output
|
||||
$downloadedNodeVersion = $nodeVersion
|
||||
} Catch {
|
||||
If ($_.Exception.Response -And $_.Exception.Response.StatusCode -eq "NotFound") {
|
||||
Write-Output "No arm64 node.lib found for Node Windows $nodeVersion, trying fallback version $fallbackVersion..."
|
||||
Invoke-WebRequest -Uri $fallbackUrl -OutFile $output
|
||||
$downloadedNodeVersion = $fallbackVersion
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Downloaded arm64 NodeJS lib v$downloadedNodeVersion to $output in $((Get-Date).Subtract($start_time).Seconds) second(s)"
|
||||
@@ -17,10 +17,9 @@ if (writeSocket(socket, dataString, strlen(dataString) + 1) != 0) { \
|
||||
|
||||
// This is a list of valid environment variables that GitHub Desktop might
|
||||
// send or expect to receive.
|
||||
#define NUMBER_OF_VALID_ENV_VARS 5
|
||||
#define NUMBER_OF_VALID_ENV_VARS 4
|
||||
static const char *sValidEnvVars[NUMBER_OF_VALID_ENV_VARS] = {
|
||||
"DESKTOP_TRAMPOLINE_IDENTIFIER",
|
||||
"DESKTOP_PORT",
|
||||
"DESKTOP_TRAMPOLINE_TOKEN",
|
||||
"DESKTOP_USERNAME",
|
||||
"DESKTOP_ENDPOINT",
|
||||
@@ -33,8 +32,8 @@ int isValidEnvVar(char *env) {
|
||||
|
||||
// Make sure that not only the passed env var string starts with the
|
||||
// candidate contesnts, but also that there is a '=' character right after:
|
||||
// Valid: "DESKTOP_PORT=50"
|
||||
// Not valid: "DESKTOP_PORT_SOMETHING=50"
|
||||
// Valid: "DESKTOP_USERNAME=sergiou87"
|
||||
// Not valid: "DESKTOP_USERNAME_SOMETHING=sergiou87"
|
||||
if (strncmp(env, candidate, strlen(candidate)) == 0
|
||||
&& strlen(env) > strlen(candidate)
|
||||
&& env[strlen(candidate)] == '=') {
|
||||
@@ -67,7 +66,9 @@ int runTrampolineClient(SOCKET *outSocket, int argc, char **argv, char **envp) {
|
||||
*outSocket = socket;
|
||||
|
||||
if (connectSocket(socket, desktopPort) != 0) {
|
||||
printSocketError("ERROR: Couldn't connect to 127.0.0.1:%d", desktopPort);
|
||||
printSocketError("ERROR: Couldn't connect to 127.0.0.1:%d - Please make "
|
||||
"sure you don't have an antivirus or firewall blocking "
|
||||
"this connection.", desktopPort);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ int runTrampolineClient(SOCKET *outSocket, int argc, char **argv, char **envp) {
|
||||
|
||||
// TODO: send stdin stuff?
|
||||
|
||||
char buffer[BUFFER_LENGTH];
|
||||
char buffer[BUFFER_LENGTH + 1];
|
||||
size_t totalBytesRead = 0;
|
||||
ssize_t bytesRead = 0;
|
||||
|
||||
|
||||
27
src/socket.c
27
src/socket.c
@@ -6,13 +6,30 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
#define MAX_WSA_ERROR_DESCRIPTION_LENGTH 4096
|
||||
|
||||
void getWSALastErrorDescription(wchar_t *buffer, int bufferLength) {
|
||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, WSAGetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPWSTR)buffer, bufferLength - 1, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int initializeNetwork(void) {
|
||||
#ifdef WINDOWS
|
||||
// Initialize Winsock
|
||||
WSADATA wsaData;
|
||||
int result = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
if (result != NO_ERROR) {
|
||||
fprintf(stderr, "ERROR: WSAStartup failed: %d\n", result);
|
||||
wchar_t errorDescription[MAX_WSA_ERROR_DESCRIPTION_LENGTH];
|
||||
getWSALastErrorDescription(errorDescription, MAX_WSA_ERROR_DESCRIPTION_LENGTH);
|
||||
|
||||
fprintf(stderr, "ERROR: WSAStartup failed (%d). Error %ld: %ls\n",
|
||||
result, WSAGetLastError(), errorDescription);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -55,8 +72,7 @@ int readSocket(SOCKET socket, void *buffer, size_t length) {
|
||||
return recv(socket, buffer, length, 0);
|
||||
}
|
||||
|
||||
void printSocketError(char *fmt, ...)
|
||||
{
|
||||
void printSocketError(char *fmt, ...) {
|
||||
char formatted_string[4096];
|
||||
|
||||
va_list argptr;
|
||||
@@ -65,7 +81,10 @@ void printSocketError(char *fmt, ...)
|
||||
va_end(argptr);
|
||||
|
||||
#ifdef WINDOWS
|
||||
fprintf(stderr, "%s: %ld\n", formatted_string, WSAGetLastError());
|
||||
wchar_t errorDescription[MAX_WSA_ERROR_DESCRIPTION_LENGTH];
|
||||
getWSALastErrorDescription(errorDescription, MAX_WSA_ERROR_DESCRIPTION_LENGTH);
|
||||
|
||||
fprintf(stderr, "%s (%ld): %ls\n", formatted_string, WSAGetLastError(), errorDescription);
|
||||
#else
|
||||
fprintf(stderr, "%s (%d): %s\n", formatted_string, errno, strerror(errno));
|
||||
#endif
|
||||
|
||||
37
src/ssh-wrapper.c
Normal file
37
src/ssh-wrapper.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifdef WINDOWS
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Not needed on Windows, this will just create a dummy executable
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* This is a wrapper for the ssh command. It is used to make sure ssh runs without
|
||||
* a tty on macOS, allowing GitHub Desktop to intercept different prompts from
|
||||
* ssh (e.g. passphrase, adding a host to the list of known hosts...).
|
||||
* This is not necessary on more recent versions of OpenSSH (starting with v8.3)
|
||||
* which include support for the SSH_ASKPASS_REQUIRE environment variable.
|
||||
*/
|
||||
int main(int argc, char **argv) {
|
||||
pid_t child = fork();
|
||||
|
||||
if (child < 0) {
|
||||
fprintf(stderr, "Failed to fork\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (child != 0) {
|
||||
// This is the parent process. Just exit.
|
||||
return 0;
|
||||
}
|
||||
|
||||
setsid();
|
||||
return execvp("ssh", argv);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -30,6 +30,7 @@ describe('desktop-trampoline', () => {
|
||||
// done forwarding data.
|
||||
socket.end()
|
||||
})
|
||||
server.unref()
|
||||
|
||||
const startTrampolineServer = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -42,9 +43,10 @@ describe('desktop-trampoline', () => {
|
||||
|
||||
const port = await startTrampolineServer()
|
||||
const env = {
|
||||
DESKTOP_PORT_FAKE: 32123,
|
||||
DESKTOP_TRAMPOLINE_IDENTIFIER: '123456',
|
||||
DESKTOP_PORT: port,
|
||||
DESKTOP_USERNAME: 'sergiou87',
|
||||
DESKTOP_USERNAME_FAKE: 'fake-user',
|
||||
INVALID_VARIABLE: 'foo bar',
|
||||
}
|
||||
const opts = { env }
|
||||
@@ -57,7 +59,7 @@ describe('desktop-trampoline', () => {
|
||||
const outputEnv = output.slice(3)
|
||||
expect(outputEnv).toHaveLength(2)
|
||||
expect(outputEnv).toContain('DESKTOP_TRAMPOLINE_IDENTIFIER=123456')
|
||||
expect(outputEnv).toContain(`DESKTOP_PORT=${port}`)
|
||||
expect(outputEnv).toContain(`DESKTOP_USERNAME=sergiou87`)
|
||||
|
||||
server.close()
|
||||
})
|
||||
42
test/ssh-wrapper.test.js
Normal file
42
test/ssh-wrapper.test.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const { stat, access } = require('fs').promises
|
||||
const { constants } = require('fs')
|
||||
const { execFile } = require('child_process')
|
||||
const { promisify } = require('util')
|
||||
const { getSSHWrapperPath } = require('../index')
|
||||
|
||||
const sshWrapperPath = getSSHWrapperPath()
|
||||
const run = promisify(execFile)
|
||||
|
||||
describe('ssh-wrapper', () => {
|
||||
it('exists and is a regular file', async () =>
|
||||
expect((await stat(sshWrapperPath)).isFile()).toBe(true))
|
||||
|
||||
// On Windows, the binary generated is just useless, so no point to test it.
|
||||
// Also, this won't be used on Linux (for now at least), so don't bother to
|
||||
// run the tests there.
|
||||
if (process.platform !== 'darwin') {
|
||||
return
|
||||
}
|
||||
|
||||
it('can be executed by current process', () =>
|
||||
access(sshWrapperPath, constants.X_OK))
|
||||
|
||||
it('attempts to use ssh-askpass program', async () => {
|
||||
// Try to connect to github.com with a non-existent known_hosts file to force
|
||||
// ssh to prompt the user and use askpass.
|
||||
const result = await run(
|
||||
sshWrapperPath,
|
||||
['-o', 'UserKnownHostsFile=/path/to/fake/known_hosts', 'git@github.com'],
|
||||
{
|
||||
env: {
|
||||
SSH_ASKPASS: '/path/to/fake/ssh-askpass',
|
||||
DISPLAY: '.',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(result.stderr).toMatch(
|
||||
/ssh_askpass: exec\(\/path\/to\/fake\/ssh-askpass\): No such file or directory/
|
||||
)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user