From bbfac8af45384f3e2f8f4b31857bf4e14fdb98a2 Mon Sep 17 00:00:00 2001 From: Shigma <1700011071@pku.edu.cn> Date: Thu, 18 Mar 2021 00:01:23 +0800 Subject: [PATCH] feat(status): support username-password login --- .../plugin-status/client/components/card.vue | 8 ++- .../plugin-status/client/components/input.vue | 14 ++--- packages/plugin-status/client/index.ts | 32 ++++++++++- packages/plugin-status/client/main.ts | 13 +++-- .../plugin-status/client/views/home/index.vue | 8 ++- .../client/views/layout/index.vue | 1 - .../client/views/layout/navbar.vue | 31 +++++++++- .../client/views/layout/sidebar.vue | 4 +- packages/plugin-status/client/views/login.vue | 56 +++++++++++-------- .../plugin-status/client/views/profile.vue | 31 +++++++++- packages/plugin-status/server/adapter.ts | 27 ++++++--- packages/plugin-status/server/index.ts | 4 ++ packages/plugin-status/server/mysql.ts | 1 + 13 files changed, 175 insertions(+), 55 deletions(-) diff --git a/packages/plugin-status/client/components/card.vue b/packages/plugin-status/client/components/card.vue index 6db856ab73..dd8b6edfac 100644 --- a/packages/plugin-status/client/components/card.vue +++ b/packages/plugin-status/client/components/card.vue @@ -23,7 +23,7 @@ $paddingX: 1.2rem; $paddingY: 1.6rem; .k-card { - margin: 0 auto; + margin: 0 auto 2rem; width: 100%; border-radius: 8px; background: rgba(0, 0, 0, .24); @@ -39,6 +39,12 @@ $paddingY: 1.6rem; .k-card-body { padding: $paddingX $paddingY; + > :first-child { + margin-top: 0; + } + > :last-child { + margin-bottom: 0; + } } &.frameless .k-card-body { diff --git a/packages/plugin-status/client/components/input.vue b/packages/plugin-status/client/components/input.vue index ee261dbf29..552f72f32f 100644 --- a/packages/plugin-status/client/components/input.vue +++ b/packages/plugin-status/client/components/input.vue @@ -1,6 +1,6 @@ @@ -30,8 +30,8 @@ import { defineProps, ref, computed, defineEmit } from 'vue' const props = defineProps({ - prefixIcon: String, - suffixIcon: String, + prefix: String, + suffix: String, placeholder: String, disabled: Boolean, validate: Function, @@ -50,11 +50,11 @@ const invalid = ref(false) const inputStyle = computed(() => ({ fontSize: props.size + 'em', - paddingLeft: +!!(props.prefixIcon) + 1 + 'em', - paddingRight: +!!(props.suffixIcon) + 1 + 'em', + paddingLeft: +!!(props.prefix) + 1 + 'em', + paddingRight: +!!(props.suffix) + 1 + 'em', })) -const emit = defineEmit(['update:modelValue', 'focus', 'blur', 'enter']) +const emit = defineEmit(['update:modelValue', 'focus', 'blur', 'enter', 'clickPrefix', 'clickSuffix']) function onInput (event) { if (props.validate) { diff --git a/packages/plugin-status/client/index.ts b/packages/plugin-status/client/index.ts index 9d478727fc..477a28c4d4 100644 --- a/packages/plugin-status/client/index.ts +++ b/packages/plugin-status/client/index.ts @@ -1,6 +1,6 @@ /* eslint-disable no-undef */ -import { ref } from 'vue' +import { ref, watch } from 'vue' import type { User } from 'koishi-core' import type { Payload } from '~/server' @@ -20,9 +20,26 @@ export namespace storage { if (typeof localStorage === 'undefined') return localStorage.setItem(prefix + key, JSON.stringify(value)) } + + export function create(key: string, fallback?: T) { + const wrapper = ref({ ...fallback, ...get(key) }) + watch(wrapper, () => set(key, wrapper.value), { + deep: typeof fallback === 'object', + }) + return wrapper + } +} + +interface Config { + authType?: 0 | 1 + username?: string + password?: string + platform?: string + userId?: string } -export const user = ref(storage.get('user')) +export const user = storage.create('user') +export const config = storage.create('config', { authType: 0 }) export const status = ref(null) export const socket = ref(null) @@ -51,3 +68,14 @@ export function send(type: string, body: any) { export function receive(event: string, listener: (data: T) => void) { listeners[event] = listener } + +export async function sha256(password: string) { + const data = new TextEncoder().encode(password) + const buffer = await crypto.subtle.digest('SHA-256', data) + const view = new DataView(buffer) + let output = '' + for (let i = 0; i < view.byteLength; i += 4) { + output += ('00000000' + view.getUint32(i).toString(16)).slice(-8) + } + return output +} diff --git a/packages/plugin-status/client/main.ts b/packages/plugin-status/client/main.ts index 895c87abeb..23b26d3200 100644 --- a/packages/plugin-status/client/main.ts +++ b/packages/plugin-status/client/main.ts @@ -15,6 +15,7 @@ import 'element-plus/lib/theme-chalk/el-button.css' import '@fortawesome/fontawesome-free/css/fontawesome.css' import '@fortawesome/fontawesome-free/css/brands.css' +import '@fortawesome/fontawesome-free/css/regular.css' import '@fortawesome/fontawesome-free/css/solid.css' import './index.scss' @@ -22,8 +23,8 @@ import './index.scss' declare module 'vue-router' { interface RouteMeta { icon?: string - status?: boolean - auth?: boolean + hidden?: boolean + authorize?: boolean frameless?: boolean } } @@ -50,17 +51,17 @@ const router = createRouter({ }, { path: '/sandbox', name: '沙盒', - meta: { icon: 'laptop-code', auth: true }, + meta: { icon: 'laptop-code', authorize: true }, component: () => import('./views/sandbox.vue'), }, { path: '/profile', name: '资料', - meta: { icon: 'user-circle', auth: true }, + meta: { icon: 'user-circle', authorize: true, hidden: true }, component: () => import('./views/profile.vue'), }, { path: '/login', name: '登录', - meta: { icon: 'sign-in-alt', frameless: true }, + meta: { icon: 'sign-in-alt', frameless: true, hidden: true }, component: () => import('./views/login.vue'), }], }) @@ -77,7 +78,7 @@ app.use(ElCollapseTransition) app.use(router) router.beforeEach((route) => { - if (route.meta.auth && !user.value) { + if (route.meta.authorize && !user.value) { return '/login' } }) diff --git a/packages/plugin-status/client/views/home/index.vue b/packages/plugin-status/client/views/home/index.vue index cf2c843393..48b4104c1f 100644 --- a/packages/plugin-status/client/views/home/index.vue +++ b/packages/plugin-status/client/views/home/index.vue @@ -1,5 +1,5 @@