Skip to content

Commit

Permalink
Verify DMD downloads with GPG
Browse files Browse the repository at this point in the history
Fixes #5

DMD does not use HTTPS for download links, thus using GPG signature is
necessary to avoid MitM. LDC currently does not need/provide those.
  • Loading branch information
Mihails Strasuns committed Nov 1, 2019
1 parent afc4e8a commit f901112
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 12 deletions.
12 changes: 7 additions & 5 deletions lib/compiler.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
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());
});
};
Expand Down Expand Up @@ -81,7 +80,8 @@ function dmd(version) {
: minor !== undefined && minor < 69 ? `${base_url}.windows.zip`
: `${base_url}.windows.7z`,
binpath: "\\dmd2\\windows\\bin",
download_dub: download_dub
download_dub: download_dub,
sig: `${base_url}.windows.7z.sig`
};
case "linux": return {
name: "dmd",
Expand All @@ -90,7 +90,8 @@ function dmd(version) {
: minor !== undefined && minor < 69 ? `${base_url}.linux.zip`
: `${base_url}.linux.tar.xz`,
binpath: "/dmd2/linux/bin64",
download_dub: download_dub
download_dub: download_dub,
sig: `${base_url}.linux.tar.xz.sig`
};
case "darwin": return {
name: "dmd",
Expand All @@ -99,7 +100,8 @@ function dmd(version) {
: minor !== undefined && minor < 69 ? `${base_url}.osx.zip`
: `${base_url}.osx.tar.xz`,
binpath: "/dmd2/osx/bin",
download_dub: download_dub
download_dub: download_dub,
sig: `${base_url}.osx.tar.xz.sig`
};
default:
throw new Error("unsupported platform: " + process.platform);
Expand Down
31 changes: 31 additions & 0 deletions lib/gpg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"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());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const tc = __importStar(require("@actions/tool-cache"));
const util_1 = require("util");
const child_process_1 = require("child_process");
const aexec = util_1.promisify(child_process_1.exec);
function verify(file_path, sig_url) {
return __awaiter(this, void 0, void 0, function* () {
const keyring = yield tc.downloadTool("https://dlang.org/d-keyring.gpg");
const sig_path = yield tc.downloadTool(sig_url);
// Will throw on non-zero exit code:
const result = yield aexec(`gpg --verify --keyring ${keyring} --trust-model=direct --no-default-keyring ${sig_path} ${file_path}`);
console.log(result.stderr);
});
}
exports.verify = verify;
6 changes: 4 additions & 2 deletions lib/main.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
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());
});
};
Expand All @@ -18,6 +17,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core"));
const tc = __importStar(require("@actions/tool-cache"));
const gpg = __importStar(require("./gpg"));
const compiler_1 = require("./compiler");
function run() {
return __awaiter(this, void 0, void 0, function* () {
Expand All @@ -35,6 +35,8 @@ function run() {
else {
console.log(`Downloading ${descr.url}`);
const archive = yield tc.downloadTool(descr.url);
if (descr.sig)
yield gpg.verify(archive, descr.sig);
const dc_path = yield extract(descr.url, archive);
if (descr.download_dub) {
const dub = yield compiler_1.legacyDub();
Expand Down
3 changes: 1 addition & 2 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
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());
});
};
Expand Down
10 changes: 7 additions & 3 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface CompilerDescription {
version: string;
url: string;
binpath: string;
sig?: string;
download_dub?: boolean;
}

Expand Down Expand Up @@ -86,7 +87,8 @@ async function dmd(version: string): Promise<CompilerDescription> {
: minor !== undefined && minor < 69 ? `${base_url}.windows.zip`
: `${base_url}.windows.7z`,
binpath: "\\dmd2\\windows\\bin",
download_dub: download_dub
download_dub: download_dub,
sig: `${base_url}.windows.7z.sig`
};
case "linux": return {
name: "dmd",
Expand All @@ -95,7 +97,8 @@ async function dmd(version: string): Promise<CompilerDescription> {
: minor !== undefined && minor < 69 ? `${base_url}.linux.zip`
: `${base_url}.linux.tar.xz`,
binpath: "/dmd2/linux/bin64",
download_dub: download_dub
download_dub: download_dub,
sig: `${base_url}.linux.tar.xz.sig`
};
case "darwin": return {
name: "dmd",
Expand All @@ -104,7 +107,8 @@ async function dmd(version: string): Promise<CompilerDescription> {
: minor !== undefined && minor < 69 ? `${base_url}.osx.zip`
: `${base_url}.osx.tar.xz`,
binpath: "/dmd2/osx/bin",
download_dub: download_dub
download_dub: download_dub,
sig: `${base_url}.osx.tar.xz.sig`
};
default:
throw new Error("unsupported platform: " + process.platform);
Expand Down
15 changes: 15 additions & 0 deletions src/gpg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as tc from '@actions/tool-cache';
import { promisify } from 'util';
import { exec } from 'child_process';
import { rename } from 'fs';

const aexec = promisify(exec);

export async function verify(file_path: string, sig_url: string) {
const keyring = await tc.downloadTool("https://dlang.org/d-keyring.gpg");
const sig_path = await tc.downloadTool(sig_url);
// Will throw on non-zero exit code:
const result = await aexec(
`gpg --verify --keyring ${keyring} --trust-model=direct --no-default-keyring ${sig_path} ${file_path}`);
console.log(result.stderr);
}
3 changes: 3 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import { mkdirP } from '@actions/io';
import * as gpg from './gpg';

import { compiler, legacyDub } from './compiler';

Expand All @@ -24,6 +25,8 @@ async function run() {
else {
console.log(`Downloading ${descr.url}`);
const archive = await tc.downloadTool(descr.url);
if (descr.sig)
await gpg.verify(archive, descr.sig);
const dc_path = await extract(descr.url, archive);

if (descr.download_dub) {
Expand Down

0 comments on commit f901112

Please sign in to comment.