From 12562d320a83e3f8f60d78a366793d474b522c55 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Wed, 20 Mar 2019 12:18:03 -0400 Subject: install, build, make: add --verify and --sign options The --verify options of build and make check the signature of rockspec and src.rock files; the --sign option is meant to be used alongside --pack-binary-rock. --- src/luarocks/build.lua | 5 +- src/luarocks/cmd/build.lua | 32 ++++++++----- src/luarocks/cmd/install.lua | 108 +++++++++++++++++++++++++++---------------- src/luarocks/cmd/make.lua | 18 +++++++- src/luarocks/cmd/pack.lua | 18 +------- src/luarocks/deps.lua | 23 +++++++-- src/luarocks/fetch.lua | 69 +++++++++++++++++++++------ src/luarocks/pack.lua | 25 +++++++++- src/luarocks/signing.lua | 32 +++++++++++-- src/luarocks/util.lua | 1 + 10 files changed, 236 insertions(+), 95 deletions(-) diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua index 130ccd3a..14d699e5 100644 --- a/src/luarocks/build.lua +++ b/src/luarocks/build.lua @@ -19,6 +19,7 @@ build.opts = util.opts_table("build.opts", { build_only_deps = "boolean", namespace = "string?", branch = "boolean", + verify = "boolean", }) do @@ -104,13 +105,13 @@ local function process_dependencies(rockspec, opts) end if not opts.build_only_deps then if next(rockspec.build_dependencies) then - local ok, err, errcode = deps.fulfill_dependencies(rockspec, "build_dependencies", opts.deps_mode) + local ok, err, errcode = deps.fulfill_dependencies(rockspec, "build_dependencies", opts.deps_mode, opts.verify) if err then return nil, err, errcode end end end - local ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode) + local ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode, opts.verify) if err then return nil, err, errcode end diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua index 29b1bd6e..e6dc8a88 100644 --- a/src/luarocks/cmd/build.lua +++ b/src/luarocks/cmd/build.lua @@ -19,7 +19,7 @@ local make = require("luarocks.cmd.make") local cmd = require("luarocks.cmd") cmd_build.help_summary = "build/compile a rock." -cmd_build.help_arguments = "[--pack-binary-rock] [--keep] {|| []}" +cmd_build.help_arguments = "[] {|| []}" cmd_build.help = [[ Build and install a rock, compiling its C parts if any. Argument may be a rockspec file, a source rock file @@ -40,17 +40,22 @@ or the name of a rock to be fetched from a repository. --only-deps Installs only the dependencies of the rock. +--verify Verify signature of the rockspec or src.rock being + built. If the rockspec or src.rock is being downloaded, + LuaRocks will attempt to download the signature as well. + Otherwise, the signature file should be already + available locally in the same directory. + You need the signer’s public key in your local + keyring for this option to work properly. + +--sign To be used with --pack-binary-rock. Also produce + a signature file for the generated .rock file. + ]]..util.deps_mode_help() --- Build and install a rock. -- @param rock_filename string: local or remote filename of a rock. --- @param need_to_fetch boolean: true if sources need to be fetched, --- false if the rockspec was obtained from inside a source rock. --- @param deps_mode: string: Which trees to check dependencies for: --- "one" for the current default tree, "all" for all trees, --- "order" for all trees with priority >= the current default, "none" for no trees. --- @param build_only_deps boolean: true to build the listed dependencies only. --- @param namespace string?: an optional namespace +-- @param opts table: build options -- @return boolean or (nil, string, [string]): True if build was successful, -- or false and an error message and an optional error code. local function build_rock(rock_filename, opts) @@ -60,7 +65,7 @@ local function build_rock(rock_filename, opts) local ok, err, errcode local unpack_dir - unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_filename) + unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_filename, nil, opts.verify) if not unpack_dir then return nil, err, errcode end @@ -100,7 +105,7 @@ local function do_build(ns_name, version, opts) end if url:match("%.rockspec$") then - local rockspec, err, errcode = fetch.load_rockspec(url) + local rockspec, err, errcode = fetch.load_rockspec(url, nil, opts.verify) if not rockspec then return nil, err, errcode end @@ -151,10 +156,15 @@ function cmd_build.command(flags, name, version) build_only_deps = not not flags["only-deps"], namespace = flags["namespace"], branch = not not flags["branch"], + verify = not not flags["verify"], }) + if flags["sign"] and not flags["pack-binary-rock"] then + return nil, "In the build command, --sign is meant to be used only with --pack-binary-rock" + end + if flags["pack-binary-rock"] then - return pack.pack_binary_rock(name, version, function() + return pack.pack_binary_rock(name, version, flags["sign"], function() opts.build_only_deps = false local status, err, errcode = do_build(name, version, opts) if status and flags["no-doc"] then diff --git a/src/luarocks/cmd/install.lua b/src/luarocks/cmd/install.lua index 97c693d9..647dbdfd 100644 --- a/src/luarocks/cmd/install.lua +++ b/src/luarocks/cmd/install.lua @@ -14,6 +14,7 @@ local search = require("luarocks.search") local queries = require("luarocks.queries") local cfg = require("luarocks.core.cfg") local cmd = require("luarocks.cmd") +local dir = require("luarocks.dir") install.help_summary = "Install a rock." @@ -29,22 +30,40 @@ or a filename of a locally available rock. in the configuration file. --only-deps Installs only the dependencies of the rock. + --no-doc Installs the rock without its documentation. + +--verify Verify signature of the rock being installed. + If rock is being downloaded, LuaRocks will attempt + to download the signature as well. If the rock is + local, the signature file should be in the same + directory. + You need the signer’s public key in your local + keyring for this option to work properly. + ]]..util.deps_mode_help() +install.opts = util.opts_table("install.opts", { + namespace = "string?", + keep = "boolean", + force = "boolean", + force_fast = "boolean", + no_doc = "boolean", + deps_mode = "string", + verify = "boolean", +}) --- Install a binary rock. -- @param rock_file string: local or remote filename of a rock. --- @param deps_mode: string: Which trees to check dependencies for: --- "one" for the current default tree, "all" for all trees, --- "order" for all trees with priority >= the current default, "none" for no trees. --- @param namespace: string?: an optional namespace. +-- @param opts table: installation options -- @return (string, string) or (nil, string, [string]): Name and version of -- installed rock if succeeded or nil and an error message followed by an error code. -function install.install_binary_rock(rock_file, deps_mode, namespace) +function install.install_binary_rock(rock_file, opts) assert(type(rock_file) == "string") - assert(type(deps_mode) == "string") - assert(type(namespace) == "string" or namespace == nil) + assert(opts:type() == "install.opts") + + local namespace = opts.namespace + local deps_mode = opts.deps_mode local name, version, arch = path.parse_name(rock_file) if not name then @@ -55,23 +74,25 @@ function install.install_binary_rock(rock_file, deps_mode, namespace) return nil, "Incompatible architecture "..arch, "arch" end if repos.is_installed(name, version) then - repos.delete_version(name, version, deps_mode) + repos.delete_version(name, version, opts.deps_mode) end + local install_dir = path.install_dir(name, version) + local rollback = util.schedule_function(function() - fs.delete(path.install_dir(name, version)) + fs.delete(install_dir) fs.remove_dir_if_empty(path.versions_dir(name)) end) - - local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version)) + + local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, install_dir, opts.verify) if not ok then return nil, err, errcode end - - local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version)) + + local rockspec, err = fetch.load_rockspec(path.rockspec_file(name, version)) if err then return nil, "Failed loading rockspec for installed package: "..err, errcode end - if deps_mode == "none" then + if opts.deps_mode == "none" then util.warning("skipping dependency checks.") else ok, err, errcode = deps.check_external_deps(rockspec, "install") @@ -90,7 +111,7 @@ function install.install_binary_rock(rock_file, deps_mode, namespace) end if deps_mode ~= "none" then - ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", deps_mode) + ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", deps_mode, opts.verify) if err then return nil, err, errcode end end @@ -112,14 +133,13 @@ end --- Installs the dependencies of a binary rock. -- @param rock_file string: local or remote filename of a rock. --- @param deps_mode: string: Which trees to check dependencies for: --- "one" for the current default tree, "all" for all trees, --- "order" for all trees with priority >= the current default, "none" for no trees. +-- @param opts table: installation options -- @return (string, string) or (nil, string, [string]): Name and version of -- the rock whose dependencies were installed if succeeded or nil and an error message -- followed by an error code. -function install.install_binary_rock_deps(rock_file, deps_mode) +function install.install_binary_rock_deps(rock_file, opts) assert(type(rock_file) == "string") + assert(opts:type() == "install.opts") local name, version, arch = path.parse_name(rock_file) if not name then @@ -130,15 +150,17 @@ function install.install_binary_rock_deps(rock_file, deps_mode) return nil, "Incompatible architecture "..arch, "arch" end - local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version)) + local install_dir = path.install_dir(name, version) + + local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, install_dir, opts.verify) if not ok then return nil, err, errcode end - local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version)) + local rockspec, err = fetch.load_rockspec(path.rockspec_file(name, version)) if err then return nil, "Failed loading rockspec for installed package: "..err, errcode end - ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", deps_mode) + ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode, opts.verify) if err then return nil, err, errcode end util.printout() @@ -147,27 +169,24 @@ function install.install_binary_rock_deps(rock_file, deps_mode) return name, version end -local function install_rock_file_deps(filename, deps_mode) - local name, version = install.install_binary_rock_deps(filename, deps_mode) +local function install_rock_file_deps(filename, opts) + assert(opts:type() == "install.opts") + + local name, version = install.install_binary_rock_deps(filename, opts) if not name then return nil, version end - writer.check_dependencies(nil, deps_mode) + writer.check_dependencies(nil, opts.deps_mode) return name, version end -local function install_rock_file(filename, namespace, deps_mode, keep, force, force_fast, no_doc) +local function install_rock_file(filename, opts) assert(type(filename) == "string") - assert(type(namespace) == "string" or namespace == nil) - assert(type(deps_mode) == "string") - assert(type(keep) == "boolean" or keep == nil) - assert(type(force) == "boolean" or force == nil) - assert(type(force_fast) == "boolean" or force_fast == nil) - assert(type(no_doc) == "boolean" or no_doc == nil) - - local name, version = install.install_binary_rock(filename, deps_mode, namespace) + assert(opts:type() == "install.opts") + + local name, version = install.install_binary_rock(filename, opts) if not name then return nil, version end - if no_doc then + if opts.no_doc then local install_dir = path.install_dir(name, version) for _, f in ipairs(fs.list_dir(install_dir)) do local doc_dirs = { "doc", "docs" } @@ -179,12 +198,12 @@ local function install_rock_file(filename, namespace, deps_mode, keep, force, fo end end - if (not keep) and not cfg.keep_other_versions then - local ok, err = remove.remove_other_versions(name, version, force, force_fast) + if (not opts.keep) and not cfg.keep_other_versions then + local ok, err = remove.remove_other_versions(name, version, opts.force, opts.force_fast) if not ok then util.printerr(err) end end - writer.check_dependencies(nil, deps_mode) + writer.check_dependencies(nil, opts.deps_mode) return name, version end @@ -213,10 +232,19 @@ function install.command(flags, name, version) return build.command(flags, name) elseif name:match("%.rock$") then local deps_mode = deps.get_deps_mode(flags) + local opts = install.opts({ + namespace = flags["namespace"], + keep = not not flags["keep"], + force = not not flags["force"], + force_fast = not not flags["force-fast"], + no_doc = not not flags["no-doc"], + deps_mode = deps_mode, + verify = not not flags["verify"], + }) if flags["only-deps"] then - return install_rock_file_deps(name, deps_mode) + return install_rock_file_deps(name, opts) else - return install_rock_file(name, flags["namespace"], deps_mode, flags["keep"], flags["force"], flags["force-fast"], flags["no-doc"]) + return install_rock_file(name, opts) end else local url, err = search.find_suitable_rock(queries.new(name:lower(), version)) diff --git a/src/luarocks/cmd/make.lua b/src/luarocks/cmd/make.lua index 90d4f336..4d813864 100644 --- a/src/luarocks/cmd/make.lua +++ b/src/luarocks/cmd/make.lua @@ -48,6 +48,17 @@ only dependencies of the rockspec (see `luarocks help install`). rockspec. Allows to specify a different branch to fetch. Particularly for "dev" rocks. +--verify Verify signature of the rockspec or src.rock being + built. If the rockspec or src.rock is being downloaded, + LuaRocks will attempt to download the signature as well. + Otherwise, the signature file should be already + available locally in the same directory. + You need the signer’s public key in your local + keyring for this option to work properly. + +--sign To be used with --pack-binary-rock. Also produce + a signature file for the generated .rock file. + ]] --- Driver function for "make" command. @@ -82,10 +93,15 @@ function make.command(flags, rockspec_filename) build_only_deps = false, namespace = flags["namespace"], branch = not not flags["branch"], + verify = not not flags["verify"], }) + if flags["sign"] and not flags["pack-binary-rock"] then + return nil, "In the make command, --sign is meant to be used only with --pack-binary-rock" + end + if flags["pack-binary-rock"] then - return pack.pack_binary_rock(name, rockspec.version, function() + return pack.pack_binary_rock(name, rockspec.version, flags["sign"], function() return build.build_rockspec(rockspec, opts) end) else diff --git a/src/luarocks/cmd/pack.lua b/src/luarocks/cmd/pack.lua index 02e554d9..7781a3bd 100644 --- a/src/luarocks/cmd/pack.lua +++ b/src/luarocks/cmd/pack.lua @@ -40,23 +40,7 @@ function cmd_pack.command(flags, arg, version) local query = queries.new(name, version) file, err = pack.pack_installed_rock(query, flags["tree"]) end - if err then - return nil, err - else - local sigfile - if flags["sign"] then - sigfile, err = signing.sign_file(file) - util.printout() - end - util.printout("Packed: "..file) - if sigfile then - util.printout("Sigature stored in: "..sigfile) - end - if err then - return nil, err - end - return true - end + return pack.report_and_sign_local_file(file, err, flags["sign"]) end return cmd_pack diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua index d9a88c2b..c2f6ab96 100644 --- a/src/luarocks/deps.lua +++ b/src/luarocks/deps.lua @@ -129,12 +129,13 @@ function deps.report_missing_dependencies(name, version, dependencies, deps_mode end end -function deps.fulfill_dependency(dep, deps_mode, name, version, rocks_provided) +function deps.fulfill_dependency(dep, deps_mode, name, version, rocks_provided, verify) assert(dep:type() == "query") assert(type(deps_mode) == "string" or deps_mode == nil) assert(type(name) == "string" or name == nil) assert(type(version) == "string" or version == nil) assert(type(rocks_provided) == "table" or rocks_provided == nil) + assert(type(verify) == "boolean" or verify == nil) deps_mode = deps_mode or "all" rocks_provided = rocks_provided or {} @@ -169,7 +170,12 @@ function deps.fulfill_dependency(dep, deps_mode, name, version, rocks_provided) return nil, "Could not satisfy dependency "..tostring(dep)..": "..search_err end util.printout("Installing "..url) - local ok, install_err, errcode = install.command({deps_mode = deps_mode, namespace = dep.namespace}, url) + local install_flags = { + deps_mode = deps_mode, + namespace = dep.namespace, + verify = verify, + } + local ok, install_err, errcode = install.command(install_flags, url) if not ok then return nil, "Failed installing dependency: "..url.." - "..install_err, errcode end @@ -183,11 +189,18 @@ end -- Packages are installed using the LuaRocks "install" command. -- Aborts the program if a dependency could not be fulfilled. -- @param rockspec table: A rockspec in table format. --- @param depskey table: Rockspec key to fetch to get dependency table. +-- @param depskey string: Rockspec key to fetch to get dependency table. +-- @param deps_mode string +-- @param verify boolean -- @return boolean or (nil, string, [string]): True if no errors occurred, or -- nil and an error message if any test failed, followed by an optional -- error code. -function deps.fulfill_dependencies(rockspec, depskey, deps_mode) +function deps.fulfill_dependencies(rockspec, depskey, deps_mode, verify) + assert(type(rockspec) == "table") + assert(type(depskey) == "string") + assert(type(deps_mode) == "string") + assert(type(verify) == "boolean" or verify == nil) + if rockspec.supported_platforms and next(rockspec.supported_platforms) then local supported = false for _, plat in pairs(rockspec.supported_platforms) do @@ -214,7 +227,7 @@ function deps.fulfill_dependencies(rockspec, depskey, deps_mode) util.printout() for _, dep in ipairs(rockspec[depskey]) do - local ok, err = deps.fulfill_dependency(dep, deps_mode, rockspec.name, rockspec.version, rockspec.rocks_provided) + local ok, err = deps.fulfill_dependency(dep, deps_mode, rockspec.name, rockspec.version, rockspec.rocks_provided, verify) if not ok then return nil, err end diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua index cd78c327..8fa7d6a6 100644 --- a/src/luarocks/fetch.lua +++ b/src/luarocks/fetch.lua @@ -5,6 +5,7 @@ local fetch = {} local fs = require("luarocks.fs") local dir = require("luarocks.dir") local rockspecs = require("luarocks.rockspecs") +local signing = require("luarocks.signing") local persist = require("luarocks.persist") local util = require("luarocks.util") local cfg = require("luarocks.core.cfg") @@ -120,27 +121,52 @@ function fetch.find_base_dir(file, temp_dir, src_url, src_dir) return inferred_dir, found_dir end +local function fetch_and_verify_signature_for(url, filename, tmpdir) + local sig_url = signing.signature_url(url) + local sig_file, err, errcode = fetch.fetch_url_at_temp_dir(sig_url, tmpdir) + if not sig_file then + return nil, "Could not fetch signature file for verification: " .. err, errcode + end + + local ok, err = signing.verify_signature(filename, sig_file) + if not ok then + return nil, "Failed signature verification: " .. err + end + + return fs.absolute_name(sig_file) +end + --- Obtain a rock and unpack it. -- If a directory is not given, a temporary directory will be created, -- which will be deleted on program termination. -- @param rock_file string: URL or filename of the rock. -- @param dest string or nil: if given, directory will be used as -- a permanent destination. +-- @param verify boolean: if true, download and verify signature for rockspec -- @return string or (nil, string, [string]): the directory containing the contents -- of the unpacked rock. -function fetch.fetch_and_unpack_rock(rock_file, dest) - assert(type(rock_file) == "string") +function fetch.fetch_and_unpack_rock(url, dest, verify) + assert(type(url) == "string") assert(type(dest) == "string" or not dest) - local name = dir.base_name(rock_file):match("(.*)%.[^.]*%.rock") - - local err, errcode - rock_file, err, errcode = fetch.fetch_url_at_temp_dir(rock_file,"luarocks-rock-"..name) + local name = dir.base_name(url):match("(.*)%.[^.]*%.rock") + local tmpname = "luarocks-rock-" .. name + + local rock_file, err, errcode = fetch.fetch_url_at_temp_dir(url, tmpname) if not rock_file then return nil, "Could not fetch rock file: " .. err, errcode end + local sig_file + if verify then + sig_file, err = fetch_and_verify_signature_for(url, rock_file, tmpname) + if err then + return nil, err + end + end + rock_file = fs.absolute_name(rock_file) + local unpack_dir if dest then unpack_dir = dest @@ -163,6 +189,12 @@ function fetch.fetch_and_unpack_rock(rock_file, dest) if not ok then return nil, "Failed unpacking rock file: " .. rock_file .. ": " .. err end + if sig_file then + ok, err = fs.copy(sig_file, ".") + if not ok then + return nil, "Failed copying signature file" + end + end fs.pop_dir() return unpack_dir end @@ -210,35 +242,44 @@ end -- @param filename string: Local or remote filename of a rockspec. -- @param location string or nil: Where to download. If not given, -- a temporary dir is created. +-- @param verify boolean: if true, download and verify signature for rockspec -- @return table or (nil, string, [string]): A table representing the rockspec -- or nil followed by an error message and optional error code. -function fetch.load_rockspec(filename, location) - assert(type(filename) == "string") +function fetch.load_rockspec(url, location, verify) + assert(type(url) == "string") local name - local basename = dir.base_name(filename) + local basename = dir.base_name(url) if basename == "rockspec" then name = "rockspec" else name = basename:match("(.*)%.rockspec") if not name then - return nil, "Filename '"..filename.."' does not look like a rockspec." + return nil, "Filename '"..url.."' does not look like a rockspec." end end - - local err, errcode + + local tmpname = "luarocks-rockspec-"..name + local filename, err, errcode if location then local ok, err = fs.change_dir(location) if not ok then return nil, err end - filename, err = fetch.fetch_url(filename) + filename, err = fetch.fetch_url(url) fs.pop_dir() else - filename, err, errcode = fetch.fetch_url_at_temp_dir(filename,"luarocks-rockspec-"..name) + filename, err, errcode = fetch.fetch_url_at_temp_dir(url, tmpname) end if not filename then return nil, err, errcode end + if verify then + local _, err = fetch_and_verify_signature_for(url, filename, tmpname) + if err then + return nil, err + end + end + return fetch.load_local_rockspec(filename) end diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua index 3955af3d..336b9167 100644 --- a/src/luarocks/pack.lua +++ b/src/luarocks/pack.lua @@ -14,6 +14,7 @@ local util = require("luarocks.util") local dir = require("luarocks.dir") local manif = require("luarocks.manif") local search = require("luarocks.search") +local signing = require("luarocks.signing") --- Create a source rock. -- Packages a rockspec and its required source files in a rock @@ -125,7 +126,26 @@ function pack.pack_installed_rock(query, tree) return rock_file end -function pack.pack_binary_rock(name, version, cmd) +function pack.report_and_sign_local_file(file, err, sign) + if err then + return nil, err + end + local sigfile + if sign then + sigfile, err = signing.sign_file(file) + util.printout() + end + util.printout("Packed: "..file) + if sigfile then + util.printout("Sigature stored in: "..sigfile) + end + if err then + return nil, err + end + return true +end + +function pack.pack_binary_rock(name, version, sign, cmd) -- The --pack-binary-rock option for "luarocks build" basically performs -- "luarocks build" on a temporary tree and then "luarocks pack". The @@ -150,7 +170,8 @@ function pack.pack_binary_rock(name, version, cmd) rname, rversion = name, version end local query = queries.new(rname, rversion) - return pack.pack_installed_rock(query, temp_dir) + local file, err = pack.pack_installed_rock(query, temp_dir) + return pack.report_and_sign_local_file(file, err, sign) end return pack diff --git a/src/luarocks/signing.lua b/src/luarocks/signing.lua index 7503768e..2e61041e 100644 --- a/src/luarocks/signing.lua +++ b/src/luarocks/signing.lua @@ -3,13 +3,25 @@ local signing = {} local cfg = require("luarocks.core.cfg") local fs = require("luarocks.fs") -function signing.sign_file(file) +local function get_gpg() local vars = cfg.variables - local gpg_ok, err = fs.is_tool_available(vars.GPG, "gpg") + local gpg = vars.GPG + local gpg_ok, err = fs.is_tool_available(gpg, "gpg") if not gpg_ok then return nil, err end - local gpg = vars.GPG + return gpg +end + +function signing.signature_url(url) + return url .. ".asc" +end + +function signing.sign_file(file) + local gpg, err = get_gpg() + if not gpg then + return nil, err + end local sigfile = file .. ".asc" if fs.execute(gpg, "--armor", "--output", sigfile, "--detach-sign", file) then @@ -19,4 +31,18 @@ function signing.sign_file(file) end end +function signing.verify_signature(file, sigfile) + local gpg, err = get_gpg() + if not gpg then + return nil, err + end + + if fs.execute(gpg, "--verify", sigfile, file) then + return true + else + return nil, "GPG returned a verification error" + end + +end + return signing diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua index e370e688..2ad59d46 100644 --- a/src/luarocks/util.lua +++ b/src/luarocks/util.lua @@ -162,6 +162,7 @@ local supported_flags = { ["tree"] = "", ["user-config"] = true, ["verbose"] = true, + ["verify"] = true, ["version"] = true, } -- cgit v1.2.3-55-g6feb