commit 4d95a03: [Project] Improve keys creation in rspamadm vault

Vsevolod Stakhov vsevolod at highsecure.ru
Mon Apr 29 17:14:03 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-04-29 18:12:08 +0100
URL: https://github.com/rspamd/rspamd/commit/4d95a0327becd78123212a2adf0138e08c4fac7d (HEAD -> master)

[Project] Improve keys creation in rspamadm vault

---
 lualib/rspamadm/vault.lua | 134 ++++++++++++++++++++++++++++++----------------
 1 file changed, 88 insertions(+), 46 deletions(-)

diff --git a/lualib/rspamadm/vault.lua b/lualib/rspamadm/vault.lua
index 98f0fef99..9c01624fc 100644
--- a/lualib/rspamadm/vault.lua
+++ b/lualib/rspamadm/vault.lua
@@ -121,20 +121,28 @@ local function is_http_error(err, data)
   return err or (math.floor(data.code / 100) ~= 2)
 end
 
+local function parse_vault_reply(data)
+  local p = ucl.parser()
+  local res,parser_err = p:parse_string(data)
+
+  if not res then
+    return nil,parser_err
+  else
+    return p:get_object(),nil
+  end
+end
+
 local function maybe_print_vault_data(opts, data, func)
   if data then
-    local p = ucl.parser()
-    local res,parser_err = p:parse_string(data)
+    local res,parser_err = parse_vault_reply(data)
 
     if not res then
       printf('vault reply for cannot be parsed: %s', parser_err)
     else
-      local obj = p:get_object()
-
       if func then
-        printf(ucl.to_format(func(obj), opts.output))
+        printf(ucl.to_format(func(res), opts.output))
       else
-        printf(ucl.to_format(obj, opts.output))
+        printf(ucl.to_format(res, opts.output))
       end
     end
   else
@@ -149,7 +157,7 @@ local function print_dkim_txt_record(b64, selector, alg)
   if #b64 < 255 then
     labels = {'"' .. b64 .. '"'}
   else
-    for sl=1,#b64,255 do
+    for sl=1,#b64,256 do
       table.insert(labels, '"' .. b64:sub(sl, sl + 255) .. '"')
     end
   end
@@ -234,6 +242,60 @@ local function genkey(opts)
   return cr.gen_dkim_keypair(opts.algorithm, opts.bits)
 end
 
+local function create_and_push_key(opts, domain, existing)
+  local uri = vault_url(opts, domain)
+  local sk,pk = genkey(opts)
+
+  local res = {
+    selectors = {
+      [1] = {
+        selector = opts.selector,
+        domain = domain,
+        key = tostring(sk),
+        alg = opts.algorithm,
+      }
+    }
+  }
+
+  for _,sel in ipairs(existing) do
+    res.selectors[#res.selectors + 1] = sel
+  end
+
+  if opts.expire then
+    res.selectors[1].valid_end = os.time() + opts.expire * 3600 * 24
+  end
+
+  local err,data = rspamd_http.request{
+    config = rspamd_config,
+    ev_base = rspamadm_ev_base,
+    session = rspamadm_session,
+    resolver = rspamadm_dns_resolver,
+    url = uri,
+    method = 'put',
+    headers = {
+      ['X-Vault-Token'] = opts.token
+    },
+    body = {
+      ucl.to_format(res, 'json-compact')
+    },
+  }
+
+  if is_http_error(err, data) then
+    printf('cannot get request to the vault (%s), HTTP error code %s', uri, data.code)
+    maybe_print_vault_data(opts, data.content)
+    os.exit(1)
+  else
+    maybe_printf(opts,'stored key for: %s, selector: %s', domain, opts.selector)
+    maybe_printf(opts, 'please place the corresponding public key as following:')
+
+    if opts.silent then
+      printf('%s', pk)
+    else
+      print_dkim_txt_record(tostring(pk), opts.selector, opts.algorithm)
+    end
+  end
+end
+
 local function newkey_handler(opts, domain)
   local uri = vault_url(opts, domain)
 
@@ -254,51 +316,31 @@ local function newkey_handler(opts, domain)
     }
   }
 
-  if is_http_error(err, data) or not data.content.data then
-    local sk,pk = genkey(opts)
-
-    local res = {
-      selectors = {
-        [1] = {
-          selector = opts.selector,
-          domain = domain,
-          key = tostring(sk),
-          alg = opts.algorithm,
-        }
-      }
-    }
+  if is_http_error(err, data) or not data.content then
+    create_and_push_key(opts, domain,{})
+  else
+    -- Key exists
+    local rep = parse_vault_reply(data.content)
 
-    if opts.expire then
-      res.selectors[1].valid_end = os.time() + opts.expire * 3600 * 24
+    if not rep or not rep.data then
+      printf('cannot parse reply for %s: %s', uri, data.content)
+      os.exit(1)
     end
 
-    err,data = rspamd_http.request{
-      config = rspamd_config,
-      ev_base = rspamadm_ev_base,
-      session = rspamadm_session,
-      resolver = rspamadm_dns_resolver,
-      url = uri,
-      method = 'put',
-      headers = {
-        ['X-Vault-Token'] = opts.token
-      },
-      body = {
-        ucl.to_format(res, 'json-compact')
-      },
-    }
+    local elts = rep.data.selectors
 
-    if is_http_error(err, data) then
-      printf('cannot get request to the vault (%s), HTTP error code %s', uri, data.code)
-      maybe_print_vault_data(opts, data.content)
-      os.exit(1)
-    else
-      maybe_printf(opts,'stored key for: %s, selector: %s', domain, opts.selector)
-      maybe_printf(opts, 'please place the corresponding public key as following:')
+    if not elts then
+      create_and_push_key(opts, domain,{})
+      os.exit(0)
+    end
 
-      if opts.silent then
-        printf('%s', pk)
+    for _,sel in ipairs(elts) do
+      if sel.alg == opts.algorithm then
+        printf('key with the specific algorithm %s is already presented at %s selector for %s domain',
+            opts.algorithm, sel.selector, domain)
+        os.exit(1)
       else
-        print_dkim_txt_record(tostring(pk), opts.selector, opts.algorithm)
+        create_and_push_key(opts, domain, elts)
       end
     end
   end


More information about the Commits mailing list