# © 2021 Florian Kantelberg - initOS GmbH # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging from odoo import _, http from odoo.exceptions import AccessDenied from odoo.http import request _logger = logging.getLogger(__name__) class Controller(http.Controller): @http.route("/vault/inbox/", type="http", auth="public") def vault_inbox(self, token): ctx = {"disable_footer": True, "token": token} # Find the right token inbox = request.env["vault.inbox"].sudo().find_inbox(token) user = request.env["res.users"].sudo().find_user_of_inbox(token) if len(inbox) == 1 and inbox.accesses > 0: ctx.update({"name": inbox.name, "public": inbox.user_id.active_key.public}) elif len(inbox) == 0 and len(user) == 1: ctx["public"] = user.active_key.public # A valid token would mean we found a public key if not ctx.get("public"): ctx["error"] = _("Invalid token") return request.render("vault.inbox", ctx) # Just render if GET method if request.httprequest.method != "POST": return request.render("vault.inbox", ctx) # Check the param name = request.params.get("name") secret = request.params.get("encrypted") secret_file = request.params.get("encrypted_file") filename = request.params.get("filename") iv = request.params.get("iv") key = request.params.get("key") if not name: ctx["error"] = _("Please specify a name") return request.render("vault.inbox", ctx) if not secret and not secret_file: ctx["error"] = _("No secret found") return request.render("vault.inbox", ctx) if secret_file and not filename: ctx["error"] = _("Missing filename") return request.render("vault.inbox", ctx) if not iv or not key: ctx["error"] = _("Something went wrong with the encryption") return request.render("vault.inbox", ctx) try: inbox.store_in_inbox( name, secret, secret_file, iv, key, user, filename, ip=request.httprequest.remote_addr, ) except Exception as e: _logger.exception(e) ctx["error"] = _( "An error occured. Please contact the user or administrator" ) return request.render("vault.inbox", ctx) ctx["message"] = _("Successfully stored") return request.render("vault.inbox", ctx) @http.route("/vault/public", type="json") def vault_public(self, user_id): """Get the public key of a specific user""" user = request.env["res.users"].sudo().browse(user_id).exists() if not user or not user.keys: return {} return {"public_key": user.active_key.public} @http.route("/vault/inbox/get", auth="user", type="json") def vault_get_inbox(self): inboxes = request.env.user.inbox_ids return {inbox.token: inbox.key for inbox in inboxes} @http.route("/vault/inbox/store", auth="user", type="json") def vault_store_inbox(self, keys): if not isinstance(keys, dict): return for inbox in request.env.user.inbox_ids: key = keys.get(inbox.token) if isinstance(key, str): inbox.key = key @http.route("/vault/keys/store", auth="user", type="json") def vault_store_keys(self, **kwargs): """Store the key pair for the current user""" return request.env["res.users.key"].store(**kwargs) @http.route("/vault/keys/get", auth="user", type="json") def vault_get_keys(self): """Get the currently active key pair""" return request.env.user.get_vault_keys() @http.route("/vault/rights/get", auth="user", type="json") def vault_get_right_keys(self): """Get the master keys from the vault.right records""" rights = request.env.user.vault_right_ids return {right.vault_id.uuid: right.key for right in rights} @http.route("/vault/rights/store", auth="user", type="json") def vault_store_right_keys(self, keys): """Store the master keys to the specific vault.right records""" if not isinstance(keys, dict): return for right in request.env.user.vault_right_ids: master_key = keys.get(right.vault_id.uuid) if isinstance(master_key, str): right.sudo().key = master_key @http.route("/vault/replace", auth="user", type="json") def vault_replace(self, data): """Replace the master keys and values within a single transaction""" if not isinstance(data, list): return vault = request.env["vault"].with_context(vault_skip_log=True) for changes in data: record = vault.env[changes["model"]].browse(changes["id"]) if not record.vault_id.allowed_write: raise AccessDenied() vault |= record.vault_id if record._name in ("vault.field", "vault.file"): record.write({k: v for k, v in changes.items() if k in ["iv", "value"]}) elif record._name == "vault.right": record.write({k: v for k, v in changes.items() if k in ["key"]}) for v in vault: v._log_entry("Replaced the keys", "info") vault.sudo().write({"reencrypt_required": False})