Packages
mob_dev
0.6.13
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.37
0.3.35
0.3.34
0.3.33
0.3.28
0.3.26
0.3.23
0.3.21
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.18
0.2.17
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Development tooling for the Mob mobile framework
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/mob.plugin.sign.ex
defmodule Mix.Tasks.Mob.Plugin.Sign do
use Mix.Task
@shortdoc "Sign a mob plugin's manifest + source files"
@moduledoc """
Signs the plugin in `<dir>` (default: cwd) and writes
`priv/mob_plugin.sig`. The signature covers the loaded manifest
plus SHA-256 hashes of every file the manifest references.
mix mob.plugin.sign [--plugin <dir>]
Reads the private key for the plugin's `:name` from
`~/.mob/keys/<name>.priv`. Run `mix mob.plugin.keygen` first if you
haven't already.
After signing, the printed fingerprint can be shared with host
operators so they can run `mix mob.plugin.trust <name>` to record
trust in their `mob.exs`.
"""
alias MobDev.Plugin.{Crypto, Manifest, PrivateKeyStore, Sign, Verify}
@switches [plugin: :string]
@impl Mix.Task
def run(args) do
{opts, _, _} = OptionParser.parse(args, strict: @switches)
plugin_dir = opts[:plugin] || File.cwd!()
{name, manifest} = load_manifest!(plugin_dir)
priv = read_priv_key!(name)
case Sign.sign_plugin(plugin_dir, priv) do
:ok ->
sig_path = Sign.signature_path(plugin_dir)
print_success(plugin_dir, name, manifest, sig_path)
{:error, reason} ->
Mix.raise("signing failed: #{inspect(reason)}")
end
end
defp load_manifest!(plugin_dir) do
case Manifest.load(plugin_dir) do
{:ok, %{name: name} = manifest} when is_atom(name) and not is_nil(name) ->
{name, manifest}
{:ok, nil} ->
Mix.raise(
"no priv/mob_plugin.exs in #{plugin_dir} — a plugin needs a manifest before it can be signed"
)
{:ok, _} ->
Mix.raise("#{plugin_dir}/priv/mob_plugin.exs is missing a :name field")
{:error, reason} ->
Mix.raise("could not load plugin manifest at #{plugin_dir}: #{reason}")
end
end
defp read_priv_key!(name) do
case PrivateKeyStore.read_key(name) do
{:ok, priv} ->
priv
{:error, :missing} ->
Mix.raise(
"no private key for #{name} at #{PrivateKeyStore.key_path(name)} — " <>
"run `mix mob.plugin.keygen` first"
)
{:error, :malformed} ->
Mix.raise(
"private key at #{PrivateKeyStore.key_path(name)} is malformed " <>
"(expected base64 of raw 32 bytes)"
)
end
end
defp print_success(plugin_dir, name, _manifest, sig_path) do
fingerprint =
case Verify.load_pubkey(plugin_dir) do
{:ok, pub} -> Crypto.fingerprint(pub)
_ -> "(no priv/mob_plugin.pub; run mix mob.plugin.keygen)"
end
Mix.shell().info([
:green,
" signed ",
:reset,
"#{name}\n",
" signature: #{sig_path}\n",
" fingerprint: ",
:cyan,
fingerprint,
:reset,
"\n\nShare the fingerprint with host operators so they can run\n",
" mix mob.plugin.trust #{name}\n",
"in their host project to record trust in mob.exs.\n"
])
end
end