diff --git a/package-lock.json b/package-lock.json index 3c274ec..5c55fc1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "axios": "^1.9.0", "marked": "^15.0.7", "openai": "^4.89.0", "pinia-plugin-persistedstate": "^4.2.0" @@ -163,6 +164,17 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", @@ -444,6 +456,26 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "4.0.2", "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.2.tgz", @@ -998,6 +1030,12 @@ "integrity": "sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==", "license": "MIT" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/quansync": { "version": "0.2.10", "resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz", diff --git a/package.json b/package.json index f83ed9d..652e4a9 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "axios": "^1.9.0", "marked": "^15.0.7", "openai": "^4.89.0", "pinia-plugin-persistedstate": "^4.2.0" diff --git a/src/client.py b/src/client.py index eece7e9..98f5efb 100644 --- a/src/client.py +++ b/src/client.py @@ -36,19 +36,23 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration], if request.method.lower() == 'options': return ResponseObject(True) - - - @client.get(prefix) - def ClientIndex(): - print(wireguardConfigurations.keys()) - return render_template('client.html') @client.post(f'{prefix}/api/signup') def ClientAPI_SignUp(): data = request.json status, msg = DashboardClients.SignUp(**data) - - return ResponseObject(status, msg) + @client.post(f'{prefix}/api/signin') + def ClientAPI_SignIn(): + data = request.json + status, msg = DashboardClients.SignIn(**data) + return ResponseObject(status, msg) + + @client.get(prefix) + @login_required + def ClientIndex(): + print(wireguardConfigurations.keys()) + return render_template('client.html') + return client \ No newline at end of file diff --git a/src/dashboard.py b/src/dashboard.py index 36edf79..5d1fb26 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -1264,7 +1264,7 @@ WireguardConfigurations: dict[str, WireguardConfiguration] = {} AllPeerShareLinks: PeerShareLinks = PeerShareLinks(DashboardConfig) AllPeerJobs: PeerJobs = PeerJobs(DashboardConfig, WireguardConfigurations) -DashboardLogger: DashboardLogger = DashboardLogger(DashboardConfig) +DashboardLogger: DashboardLogger = DashboardLogger() InitWireguardConfigurationsList(startup=True) diff --git a/src/modules/DashboardClients.py b/src/modules/DashboardClients.py index 4a66c7b..bbf7c26 100644 --- a/src/modules/DashboardClients.py +++ b/src/modules/DashboardClients.py @@ -1,14 +1,23 @@ +import hashlib +import uuid + +import bcrypt +import pyotp import sqlalchemy as db -from sqlalchemy.orm import DeclarativeBase, Mapped -from sqlalchemy.testing.schema import mapped_column from .ConnectionString import ConnectionString +from .DashboardClientsTOTP import DashboardClientsTOTP +from .Utilities import ValidatePasswordStrength +from .DashboardLogger import DashboardLogger + class DashboardClients: def __init__(self): + self.logger = DashboardLogger() self.engine = db.create_engine(ConnectionString("wgdashboard")) self.metadata = db.MetaData() + self.DashboardClientsTOTP = DashboardClientsTOTP() self.dashboardClientsTable = db.Table( 'DashboardClients', self.metadata, @@ -36,8 +45,6 @@ class DashboardClients: self.metadata.create_all(self.engine) self.Clients = [] self.__getClients() - print('hi') - print(self.Clients) def __getClients(self): with self.engine.connect() as conn: @@ -49,10 +56,63 @@ class DashboardClients: ).where( self.dashboardClientsTable.c.DeletedDate is None) ).mappings().fetchall() + + def SignIn(self, Email, Password) -> tuple[bool, str]: + if not all([Email, Password]): + return False, "Please fill in all fields" + with self.engine.connect() as conn: + existingClient = conn.execute( + self.dashboardClientsTable.select().where( + self.dashboardClientsTable.c.Email == Email + ) + ).mappings().fetchone() + if existingClient: + checkPwd = bcrypt.checkpw(Password.encode("utf-8"), existingClient.get("Password").encode("utf-8")) + if checkPwd: + return True, self.DashboardClientsTOTP.GenerateToken(existingClient.get("ClientID")) + + + return False, "Email or Password is incorrect" + + def SignUp(self, Email, Password, ConfirmPassword) -> tuple[bool, str] or tuple[bool, None]: + try: + if not all([Email, Password, ConfirmPassword]): + return False, "Please fill in all fields" + if Password != ConfirmPassword: + return False, "Passwords does not match" + + with self.engine.connect() as conn: + existingClient = conn.execute( + self.dashboardClientsTable.select().where( + self.dashboardClientsTable.c.Email == Email + ) + ).mappings().fetchone() + if existingClient: + return False, "Email already signed up" + + pwStrength, msg = ValidatePasswordStrength(Password) + if not pwStrength: + return pwStrength, msg + + with self.engine.begin() as conn: + newClientUUID = str(uuid.uuid4()) + totpKey = pyotp.random_base32() + encodePassword = Password.encode('utf-8') + conn.execute( + self.dashboardClientsTable.insert().values({ + "ClientID": newClientUUID, + "Email": Email, + "Password": bcrypt.hashpw(encodePassword, bcrypt.gensalt()).decode("utf-8"), + "TotpKey": totpKey + }) + ) + conn.execute( + self.dashboardClientsInfoTable.insert().values({ + "ClientID": newClientUUID + }) + ) + except Exception as e: + self.logger.log(Status="false", Message=f"Signed up failed, reason: {str(e)}") + return False, "Signed up failed." - - - def SignUp(self, Email, Password, ConfirmPassword) -> tuple[bool, str]: - pass - - \ No newline at end of file + return True, None \ No newline at end of file diff --git a/src/modules/DashboardClientsTOTP.py b/src/modules/DashboardClientsTOTP.py new file mode 100644 index 0000000..dff96ed --- /dev/null +++ b/src/modules/DashboardClientsTOTP.py @@ -0,0 +1,44 @@ +import datetime +import hashlib +import uuid + +import sqlalchemy as db +from .ConnectionString import ConnectionString + + +class DashboardClientsTOTP: + def __init__(self): + self.engine = db.create_engine(ConnectionString("wgdashboard")) + self.metadata = db.MetaData() + self.dashboardClientsTOTPTable = db.Table( + 'DashboardClientsTOTPTokens', self.metadata, + db.Column("Token", db.String(500), primary_key=True, index=True), + db.Column("ClientID", db.String(500), index=True), + db.Column( + "ExpireTime", (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP) + ) + ) + self.metadata.create_all(self.engine) + + def GenerateToken(self, ClientID) -> str: + token = hashlib.sha512(f"{ClientID}_{datetime.datetime.now()}_{uuid.uuid4()}".encode()).hexdigest() + with self.engine.begin() as conn: + conn.execute( + self.dashboardClientsTOTPTable.update().values({ + "ExpireTime": datetime.datetime.now() + }).where( + db.and_(self.dashboardClientsTOTPTable.c.ClientID == ClientID, self.dashboardClientsTOTPTable.c.ExpireTime > datetime.datetime.now()) + ) + ) + + + conn.execute( + self.dashboardClientsTOTPTable.insert().values({ + "Token": token, + "ClientID": ClientID, + "ExpireTime": datetime.datetime.now() + datetime.timedelta(minutes=10) + }) + ) + + return token + \ No newline at end of file diff --git a/src/modules/DashboardLogger.py b/src/modules/DashboardLogger.py index d7b162c..afa4a02 100644 --- a/src/modules/DashboardLogger.py +++ b/src/modules/DashboardLogger.py @@ -8,13 +8,14 @@ from .ConnectionString import ConnectionString class DashboardLogger: - def __init__(self, DashboardConfig): + def __init__(self): self.engine = db.create_engine(ConnectionString("wgdashboard_log")) self.metadata = db.MetaData() self.dashboardLoggerTable = db.Table('DashboardLog', self.metadata, db.Column('LogID', db.String(255), nullable=False, primary_key=True), - db.Column('LogDate', (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP), + db.Column('LogDate', + (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP), server_default=db.func.now()), db.Column('URL', db.String(255)), db.Column('IP', db.String(255)), diff --git a/src/static/client/package-lock.json b/src/static/client/package-lock.json index 8c85ba6..3ef6844 100644 --- a/src/static/client/package-lock.json +++ b/src/static/client/package-lock.json @@ -8,6 +8,7 @@ "name": "client", "version": "0.0.0", "dependencies": { + "axios": "^1.9.0", "bootstrap": "^5.3.6", "bootstrap-icons": "^1.13.1", "dayjs": "^1.11.13", @@ -1553,6 +1554,23 @@ "integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==", "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/birpc": { "version": "2.3.0", "resolved": "https://registry.npmmirror.com/birpc/-/birpc-2.3.0.tgz", @@ -1646,6 +1664,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001720", "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz", @@ -1667,6 +1698,18 @@ ], "license": "CC-BY-4.0" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1777,6 +1820,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.161", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.161.tgz", @@ -1806,6 +1872,51 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.5", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.5.tgz", @@ -1921,6 +2032,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs-extra": { "version": "11.3.0", "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.0.tgz", @@ -1951,6 +2097,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1961,6 +2116,43 @@ "node": ">=6.9.0" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "9.0.1", "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-9.0.1.tgz", @@ -1988,6 +2180,18 @@ "node": ">=4" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1995,6 +2199,45 @@ "dev": true, "license": "ISC" }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", @@ -2192,6 +2435,36 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", @@ -2409,6 +2682,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", diff --git a/src/static/client/package.json b/src/static/client/package.json index 8d11562..19b8c14 100644 --- a/src/static/client/package.json +++ b/src/static/client/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.9.0", "bootstrap": "^5.3.6", "bootstrap-icons": "^1.13.1", "dayjs": "^1.11.13", diff --git a/src/static/client/src/App.vue b/src/static/client/src/App.vue index 8294dfd..65de3d6 100644 --- a/src/static/client/src/App.vue +++ b/src/static/client/src/App.vue @@ -5,13 +5,19 @@ import NotificationList from "@/components/notification/notificationList.vue"; @@ -19,12 +25,12 @@ import NotificationList from "@/components/notification/notificationList.vue"; diff --git a/src/static/client/src/assets/main.css b/src/static/client/src/assets/main.css index 0d745ed..0e1d730 100644 --- a/src/static/client/src/assets/main.css +++ b/src/static/client/src/assets/main.css @@ -56,4 +56,20 @@ ::-webkit-scrollbar { display: none; +} + +.slide-right-enter-active, +.slide-right-leave-active { + transition: all 0.3s cubic-bezier(0.82, 0.58, 0.17, 1); +} +.slide-right-enter-from, +.slide-right-leave-to{ + opacity: 0; +} + +.slide-right-enter-from{ + transform: translateX(-20px); +} +.slide-right-leave-to{ + transform: translateX(20px); } \ No newline at end of file diff --git a/src/static/client/src/components/notification/notification.vue b/src/static/client/src/components/notification/notification.vue index b186457..54a5d5d 100644 --- a/src/static/client/src/components/notification/notification.vue +++ b/src/static/client/src/components/notification/notification.vue @@ -16,7 +16,7 @@ const show = () => { props.notificationData.show = true; timeout = setTimeout(() => { dismiss() - }, 50000) + }, 5000) } const clearTime = () => clearTimeout(timeout) const dismiss = () => props.notificationData.show = false; @@ -57,7 +57,7 @@ onMounted(() => { \ No newline at end of file diff --git a/src/static/client/vite.config.js b/src/static/client/vite.config.js index 604eda8..f6318a2 100644 --- a/src/static/client/vite.config.js +++ b/src/static/client/vite.config.js @@ -25,8 +25,7 @@ export default defineConfig({ }, server:{ proxy: { - '/api': proxy, - '/fileDownload':proxy + '/client': proxy, }, host: '0.0.0.0' },