From e725fb847324d5cf3b80bfa8def89353cc3ecf1f Mon Sep 17 00:00:00 2001
From: fxiang21 <fxiang21@126.com>
Date: Fri, 27 Oct 2023 18:28:23 +0800
Subject: [PATCH] feat: add inner password storage

---
 cmdb-api/api/app.py               |  2 ++
 cmdb-api/api/extensions.py        |  3 +++
 cmdb-api/api/lib/secrets/inner.py | 38 +++++++++----------------------
 3 files changed, 16 insertions(+), 27 deletions(-)

diff --git a/cmdb-api/api/app.py b/cmdb-api/api/app.py
index 537abda..348a6b5 100644
--- a/cmdb-api/api/app.py
+++ b/cmdb-api/api/app.py
@@ -18,6 +18,7 @@ from flask.json.provider import DefaultJSONProvider
 
 import api.views.entry
 from api.extensions import (bcrypt, cache, celery, cors, db, es, login_manager, migrate, rd)
+from api.extensions import inner_secrets
 from api.flask_cas import CAS
 from api.models.acl import User
 
@@ -125,6 +126,7 @@ def register_extensions(app):
 
     app.config.update(app.config.get("CELERY"))
     celery.conf.update(app.config)
+    inner_secrets.init_app(app)
 
 
 def register_blueprints(app):
diff --git a/cmdb-api/api/extensions.py b/cmdb-api/api/extensions.py
index f540c21..0dd13ad 100644
--- a/cmdb-api/api/extensions.py
+++ b/cmdb-api/api/extensions.py
@@ -12,6 +12,8 @@ from flask_sqlalchemy import SQLAlchemy
 from api.lib.utils import ESHandler
 from api.lib.utils import RedisHandler
 
+from api.lib.secrets.inner import KeyManage
+
 bcrypt = Bcrypt()
 login_manager = LoginManager()
 db = SQLAlchemy(session_options={"autoflush": False})
@@ -21,3 +23,4 @@ celery = Celery()
 cors = CORS(supports_credentials=True)
 rd = RedisHandler()
 es = ESHandler()
+inner_secrets = KeyManage()
diff --git a/cmdb-api/api/lib/secrets/inner.py b/cmdb-api/api/lib/secrets/inner.py
index 5caa6cf..6394373 100644
--- a/cmdb-api/api/lib/secrets/inner.py
+++ b/cmdb-api/api/lib/secrets/inner.py
@@ -22,7 +22,6 @@ from flask import current_app
 global_iv_length = 16
 global_key_shares = 5  # Number of generated key shares
 global_key_threshold = 3  # Minimum number of shares required to rebuild the key
-global_shares = []
 
 backend_root_key_name = "root_key"
 backend_encrypt_key_name = "encrypt_key"
@@ -30,7 +29,6 @@ backend_root_key_salt_name = "root_key_salt"
 backend_encrypt_key_salt_name = "encrypt_key_salt"
 success = "success"
 seal_status = True
-cache = {}
 
 
 def string_to_bytes(value):
@@ -43,27 +41,9 @@ def string_to_bytes(value):
     return byte_string
 
 
-class CacheBackend:
-    def __init__(self):
-        pass
-
-    @classmethod
-    def get(cls, key):
-        global cache
-        return cache.get(key)
-
-    @classmethod
-    def add(cls, key, value):
-        cache[key] = value
-        return success, True
-
-
 class Backend:
     def __init__(self, backend=None):
-        if not backend:
-            self.backend = CacheBackend
-        else:
-            self.backend = backend
+        self.backend = backend
 
     def get(self, key):
         return self.backend.get(key)
@@ -80,6 +60,9 @@ class KeyManage:
         if backend:
             self.backend = Backend(backend)
 
+    def init_app(self, app):
+        self.auto_unseal()
+
     def hash_root_key(self, value):
         algorithm = hashes.SHA256()
         salt = self.backend.get(backend_root_key_salt_name)
@@ -166,18 +149,19 @@ class KeyManage:
                 "message": "current status is unseal, skip",
                 "status": "skip"
             }
-        global global_shares
         try:
             t = [i for i in b64decode(key)]
             v = (int("".join([chr(i) for i in t[-2:]])), bytes(t[:-2]))
-            if v not in global_shares:
-                global_shares.append(v)
-            if len(global_shares) >= global_key_threshold:
-                recovered_secret = Shamir.combine(global_shares[:global_key_threshold])
+            shares = getattr(current_app, "secrets_shares", [])
+            if v not in shares:
+                shares.append(v)
+                setattr(current_app, "secrets_shares", shares)
+            if len(shares) >= global_key_threshold:
+                recovered_secret = Shamir.combine(shares[:global_key_threshold])
                 return self.auth_root_secret(b64encode(recovered_secret))
             else:
                 return {
-                    "message": "waiting for inputting other unseal key {0}/{1}".format(len(global_shares),
+                    "message": "waiting for inputting other unseal key {0}/{1}".format(len(shares),
                                                                                        global_key_threshold),
                     "status": "waiting"
                 }