feat(login): #1300 Encrypted transmission of login password

pull/1316/head
limingwei 2 years ago
parent f041a780ef
commit 17f1856307

@ -44,9 +44,11 @@
}, },
"dependencies": { "dependencies": {
"axios": ">=0.18.1", "axios": ">=0.18.1",
"buffer": "^6.0.3",
"clipboard": "2.0.4", "clipboard": "2.0.4",
"codemirror": "5.45.0", "codemirror": "5.45.0",
"core-js": "^3.26.0", "core-js": "^3.26.0",
"crypto": "^1.0.1",
"echarts": "^5.2.2", "echarts": "^5.2.2",
"element-ui": "^2.15.7", "element-ui": "^2.15.7",
"fuse.js": "3.4.4", "fuse.js": "3.4.4",

@ -1,126 +1,157 @@
import { login } from '@/api/user'; import {login} from '@/api/user';
import { getToken, setToken, removeToken } from '@/utils/auth'; import {getToken, removeToken, setToken} from '@/utils/auth';
import router, { resetRouter } from '@/router'; import router, {resetRouter} from '@/router';
import {Buffer} from 'buffer'
import crypto from 'crypto'
const state = { const state = {
token: getToken(), token: getToken(),
name: '', name: '',
avatar: '', avatar: '',
introduction: '', introduction: '',
roles: [], roles: [],
}; };
const mutations = { const mutations = {
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token; state.token = token;
}, },
SET_INTRODUCTION: (state, introduction) => { SET_INTRODUCTION: (state, introduction) => {
state.introduction = introduction; state.introduction = introduction;
}, },
SET_NAME: (state, name) => { SET_NAME: (state, name) => {
state.name = name; state.name = name;
}, },
SET_AVATAR: (state, avatar) => { SET_AVATAR: (state, avatar) => {
state.avatar = avatar; state.avatar = avatar;
}, },
SET_ROLES: (state, roles) => { SET_ROLES: (state, roles) => {
state.roles = roles; state.roles = roles;
}, },
}; };
const actions = { const actions = {
// user login // user login
login({ commit }, userInfo) { login({commit}, userInfo) {
const { username, password } = userInfo; const {username, password} = userInfo;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password, rememberMe: 1 }) let key = actions.genKey();
.then((response) => { let encodePassword = actions.encrypt(password, key)
const { data } = response; console.log("enpwd:", encodePassword)
const { roles } = response; key = key.split("").reverse().join("")
commit('SET_TOKEN', data);
localStorage.setItem('roles', JSON.stringify(roles)); login({username: username.trim(), password: encodePassword, tag: key, rememberMe: 1})
localStorage.setItem('USER_ROLE', roles[0]); .then((response) => {
setToken(data); const {data} = response;
resolve(); const {roles} = response;
}) commit('SET_TOKEN', data);
.catch((error) => { localStorage.setItem('roles', JSON.stringify(roles));
alert('登录失败'); localStorage.setItem('USER_ROLE', roles[0]);
reject(error); setToken(data);
resolve();
})
.catch((error) => {
alert('登录失败');
reject(error);
});
});
},
// get user info
getInfo({commit, state}) {
return new Promise((resolve, reject) => {
const data = {};
data.roles = JSON.parse(localStorage.getItem('roles'));
commit('SET_ROLES', data.roles);
resolve(data);
});
},
// user logout
logout({commit, state}) {
// return new Promise((resolve, reject) => {
// logout(state.token).then(() => {
// commit('SET_TOKEN', '')
// commit('SET_ROLES', [])
// removeToken()
// resetRouter()
// resolve()
// }).catch(error => {
// reject(error)
// })
// })
return new Promise((resolve) => {
commit('SET_TOKEN', '');
commit('SET_ROLES', []);
removeToken();
resetRouter();
resolve();
});
},
// remove token
resetToken({commit}) {
return new Promise((resolve) => {
commit('SET_TOKEN', '');
commit('SET_ROLES', []);
removeToken();
resolve();
});
},
// dynamically modify permissions
changeRoles({commit, dispatch}, role) {
return new Promise(async (resolve) => {
const token = role + '-token';
commit('SET_TOKEN', token);
setToken(token);
const {roles} = await dispatch('getInfo');
resetRouter();
// generate accessible routes map based on roles
const accessRoutes = await dispatch('permission/generateRoutes', roles, {root: true});
// dynamically add accessible routes
router.addRoutes(accessRoutes);
// reset visited views and cached views
dispatch('tagsView/delAllViews', null, {root: true});
resolve();
}); });
}); },
}, genKey() {
let chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
// get user info let result = '';
getInfo({ commit, state }) { for (let i = 16; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
return new Promise((resolve, reject) => { return result;
const data = {}; },
data.roles = JSON.parse(localStorage.getItem('roles')); encrypt(msg, key) {
commit('SET_ROLES', data.roles); try {
resolve(data); let pwd = Buffer.from(key)
}); let iv = crypto.randomBytes(12)
}, let cipher = crypto.createCipheriv('aes-128-gcm', pwd, iv)
let enc = cipher.update(msg, 'utf8', 'base64')
// user logout enc += cipher.final('base64')
logout({ commit, state }) { let tags = cipher.getAuthTag()
// return new Promise((resolve, reject) => { enc = Buffer.from(enc, 'base64')
// logout(state.token).then(() => { let totalLength = iv.length + enc.length + tags.length
// commit('SET_TOKEN', '') let bufferMsg = Buffer.concat([iv, enc, tags], totalLength)
// commit('SET_ROLES', []) return bufferMsg.toString('base64')
// removeToken() } catch (e) {
// resetRouter() console.log("Encrypt is error", e)
// resolve() return null
// }).catch(error => { }
// reject(error) },
// })
// })
return new Promise((resolve) => {
commit('SET_TOKEN', '');
commit('SET_ROLES', []);
removeToken();
resetRouter();
resolve();
});
},
// remove token
resetToken({ commit }) {
return new Promise((resolve) => {
commit('SET_TOKEN', '');
commit('SET_ROLES', []);
removeToken();
resolve();
});
},
// dynamically modify permissions
changeRoles({ commit, dispatch }, role) {
return new Promise(async (resolve) => {
const token = role + '-token';
commit('SET_TOKEN', token);
setToken(token);
const { roles } = await dispatch('getInfo');
resetRouter();
// generate accessible routes map based on roles
const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true });
// dynamically add accessible routes
router.addRoutes(accessRoutes);
// reset visited views and cached views
dispatch('tagsView/delAllViews', null, { root: true });
resolve();
});
},
}; };
export default { export default {
namespaced: true, namespaced: true,
state, state,
mutations, mutations,
actions, actions,
}; };

@ -170,8 +170,8 @@ export default {
this.$router.push({ path: this.redirect || '/', query: this.otherQuery }); this.$router.push({ path: this.redirect || '/', query: this.otherQuery });
this.loading = false; this.loading = false;
}) })
.catch(() => { .catch((e) => {
console.log('error catch.'); console.log('error catch.',e);
this.loading = false; this.loading = false;
}); });
} else { } else {

@ -19,12 +19,14 @@ package cn.hippo4j.auth.filter;
import cn.hippo4j.auth.model.biz.user.JwtUser; import cn.hippo4j.auth.model.biz.user.JwtUser;
import cn.hippo4j.auth.model.biz.user.LoginUser; import cn.hippo4j.auth.model.biz.user.LoginUser;
import cn.hippo4j.auth.toolkit.AESUtil;
import cn.hippo4j.auth.toolkit.JwtTokenUtil; import cn.hippo4j.auth.toolkit.JwtTokenUtil;
import cn.hippo4j.auth.toolkit.ReturnT; import cn.hippo4j.auth.toolkit.ReturnT;
import cn.hippo4j.common.toolkit.JSONUtil; import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.server.common.base.Results; import cn.hippo4j.server.common.base.Results;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.codec.DecodingException;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -38,6 +40,7 @@ import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -69,10 +72,17 @@ public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilte
Authentication authenticate = null; Authentication authenticate = null;
try { try {
LoginUser loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class); LoginUser loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
String key = new StringBuffer(loginUser.getTag()).reverse().toString();
String password = AESUtil.decrypt(loginUser.getPassword(), key);
loginUser.setPassword(password);
request.setAttribute("loginUser", loginUser); request.setAttribute("loginUser", loginUser);
rememberMe.set(loginUser.getRememberMe()); rememberMe.set(loginUser.getRememberMe());
authenticate = authenticationManager.authenticate( authenticate = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), new ArrayList())); new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), new ArrayList()));
} catch (GeneralSecurityException e) {
log.warn("Password decode exception: {}", e.getMessage());
throw new DecodingException(e.getMessage());
} catch (UsernameNotFoundException e) { } catch (UsernameNotFoundException e) {
log.warn("User {} not found", e.getMessage()); log.warn("User {} not found", e.getMessage());
throw e; throw e;

@ -24,6 +24,10 @@ import lombok.Data;
*/ */
@Data @Data
public class LoginUser { public class LoginUser {
/**
* encode key reverse
*/
private String tag;
/** /**
* username * username

@ -0,0 +1,92 @@
package cn.hippo4j.auth.toolkit;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import lombok.experimental.UtilityClass;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;
/**
* Aes
*
* @author <a href="mailto:SerenitySir@outlook.com">Serenity</a>
* @date 2023/5/21 14:37
* @since JDK1.8+
*/
@UtilityClass
public class AESUtil {
private static final String AES_GCM_CIPHER = "AES/GCM/PKCS5Padding";
/**
*
*
* @param data
* @param key
* @return byte[]
*/
public static byte[] encrypt(byte[] data, byte[] key) throws GeneralSecurityException {
SecretKeySpec sKeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER);
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
byte[] iv = cipher.getIV();
byte[] encryptData = cipher.doFinal(data);
byte[] message = new byte[12 + data.length + 16];
System.arraycopy(iv, 0, message, 0, 12);
System.arraycopy(encryptData, 0, message, 12, encryptData.length);
return message;
}
/**
*
*
* @param data
* @param key
* @return byte[]
*/
public static byte[] decrypt(byte[] data, byte[] key) throws GeneralSecurityException{
GCMParameterSpec iv = new GCMParameterSpec(128, data, 0, 12);
Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER);
SecretKey key2 = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, key2, iv);
return cipher.doFinal(data, 12, data.length - 12);
}
/**
*
*
* @param data
* @param key
* @return String
*/
public static String encrypt(String data, String key) throws GeneralSecurityException {
byte[] valueByte = encrypt(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(valueByte);
}
/**
*
*
* @param data base64
* @param key
* @return String
*/
public static String decrypt(String data, String key) throws GeneralSecurityException {
byte[] originalData = Base64.getDecoder().decode(data.getBytes());
byte[] valueByte = decrypt(originalData, key.getBytes(StandardCharsets.UTF_8));
return new String(valueByte);
}
/**
*
*
* @return
*/
public static String generateRandomKey() {
return IdWorker.get32UUID().substring(0, 16);
}
}

File diff suppressed because one or more lines are too long

@ -1 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none} .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none}.el-table--border th.el-table__cell{padding:0;height:40px}.el-table .cell{line-height:normal}

@ -1 +1 @@
.social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-7cb824ba]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-7cb824ba]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-7cb824ba]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-7cb824ba]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-7cb824ba]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-7cb824ba]{position:relative}.login-container .title-container .title[data-v-7cb824ba]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-7cb824ba]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-7cb824ba]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-7cb824ba]{display:none}} .social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-c62df1a8]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-c62df1a8]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-c62df1a8]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-c62df1a8]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-c62df1a8]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-c62df1a8]{position:relative}.login-container .title-container .title[data-v-c62df1a8]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-c62df1a8]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-c62df1a8]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-c62df1a8]{display:none}}

@ -1 +1 @@
.github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}@-webkit-keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:none;animation:none}.github-corner .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}}.panel-group[data-v-b4165a68]{margin-top:18px}.panel-group .card-panel-col[data-v-b4165a68]{margin-bottom:32px}.panel-group .card-panel[data-v-b4165a68]{height:108px;cursor:pointer;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel:hover .card-panel-icon-wrapper[data-v-b4165a68]{color:#fff}.panel-group .card-panel:hover .icon-people[data-v-b4165a68]{background:#dae8d6}.panel-group .card-panel:hover .icon-message[data-v-b4165a68]{background:#36a3f7}.panel-group .card-panel:hover .icon-money[data-v-b4165a68]{background:#a0a6f4}.panel-group .card-panel:hover .icon-shopping[data-v-b4165a68]{background:#dae8d6}.panel-group .card-panel .icon-people[data-v-b4165a68]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-b4165a68]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-b4165a68]{color:#a0a6f4}.panel-group .card-panel .icon-shopping[data-v-b4165a68]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-b4165a68]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-b4165a68]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-b4165a68]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-b4165a68]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-b4165a68]{font-size:20px}@media(max-width:550px){.card-panel-description[data-v-b4165a68]{display:none}.card-panel-icon-wrapper[data-v-b4165a68]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-b4165a68]{display:block;margin:14px auto!important;float:none!important}}.dashboard-editor-container[data-v-6e862226]{padding:32px;background-color:#f0f2f5;position:relative}.dashboard-editor-container .github-corner[data-v-6e862226]{position:absolute;top:0;border:0;right:0}.dashboard-editor-container .el-form-item[data-v-6e862226]{margin-bottom:5px!important;padding-bottom:20px}.dashboard-editor-container .chart-wrapper[data-v-6e862226]{background:#fff;padding:16px 16px 0;margin-bottom:32px}@media(max-width:1024px){.chart-wrapper[data-v-6e862226]{padding:8px}} .github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}@-webkit-keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes octocat-wave-data-v-fedac698{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm[data-v-fedac698]{-webkit-animation:none;animation:none}.github-corner .octo-arm[data-v-fedac698]{-webkit-animation:octocat-wave-data-v-fedac698 .56s ease-in-out;animation:octocat-wave-data-v-fedac698 .56s ease-in-out}}.panel-group[data-v-b4165a68]{margin-top:18px}.panel-group .card-panel-col[data-v-b4165a68]{margin-bottom:32px}.panel-group .card-panel[data-v-b4165a68]{height:108px;cursor:pointer;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel:hover .card-panel-icon-wrapper[data-v-b4165a68]{color:#fff}.panel-group .card-panel:hover .icon-people[data-v-b4165a68]{background:#dae8d6}.panel-group .card-panel:hover .icon-message[data-v-b4165a68]{background:#36a3f7}.panel-group .card-panel:hover .icon-money[data-v-b4165a68]{background:#a0a6f4}.panel-group .card-panel:hover .icon-shopping[data-v-b4165a68]{background:#dae8d6}.panel-group .card-panel .icon-people[data-v-b4165a68]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-b4165a68]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-b4165a68]{color:#a0a6f4}.panel-group .card-panel .icon-shopping[data-v-b4165a68]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-b4165a68]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-b4165a68]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-b4165a68]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-b4165a68]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-b4165a68]{font-size:20px}@media(max-width:550px){.card-panel-description[data-v-b4165a68]{display:none}.card-panel-icon-wrapper[data-v-b4165a68]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-b4165a68]{display:block;margin:14px auto!important;float:none!important}}.dashboard-editor-container[data-v-1cb2dce5]{padding:32px;background-color:#f0f2f5;position:relative}.dashboard-editor-container .github-corner[data-v-1cb2dce5]{position:absolute;top:0;border:0;right:0}.dashboard-editor-container .el-form-item[data-v-1cb2dce5]{margin-bottom:5px!important;padding-bottom:20px}.dashboard-editor-container .chart-wrapper[data-v-1cb2dce5]{background:#fff;padding:16px 16px 0;margin-bottom:32px}@media(max-width:1024px){.chart-wrapper[data-v-1cb2dce5]{padding:8px}}

@ -1 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.dashboard-editor-container[data-v-69dc5993]{padding:32px;background-color:#f0f2f5;position:relative;min-height:100vh} .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.dashboard-editor-container[data-v-5ce168aa]{padding:32px;background-color:#f0f2f5;position:relative;min-height:100vh}

@ -1 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none}[data-v-41b2dc5c]::-webkit-scrollbar{width:8px;height:8px}[data-v-41b2dc5c]::-webkit-scrollbar-track{border-radius:5px;background:rgba(0,0,0,.06);-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,.08)}[data-v-41b2dc5c]::-webkit-scrollbar-thumb{border-radius:5px;background:rgba(0,0,0,.12);-webkit-box-shadow:inset 0 0 10px rgba(0,0,0,.2)}.stack-info[data-v-41b2dc5c]{height:400px;overflow:auto}.stack-info>li[data-v-41b2dc5c]{margin-bottom:24px}.stack-info>li p[data-v-41b2dc5c]:first-child{color:#06f;font-weight:600;margin-top:10px}.stack-info>li ul[data-v-41b2dc5c]{margin-left:30px}.stack-info>li ul li[data-v-41b2dc5c]{color:#fc5531;text-align:justify;margin:10px auto} .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none}[data-v-a1fe05c0]::-webkit-scrollbar{width:8px;height:8px}[data-v-a1fe05c0]::-webkit-scrollbar-track{border-radius:5px;background:rgba(0,0,0,.06);-webkit-box-shadow:inset 0 0 5px rgba(0,0,0,.08)}[data-v-a1fe05c0]::-webkit-scrollbar-thumb{border-radius:5px;background:rgba(0,0,0,.12);-webkit-box-shadow:inset 0 0 10px rgba(0,0,0,.2)}.stack-info[data-v-a1fe05c0]{height:400px;overflow:auto}.stack-info>li[data-v-a1fe05c0]{margin-bottom:24px}.stack-info>li p[data-v-a1fe05c0]:first-child{color:#06f;font-weight:600;margin-top:10px}.stack-info>li ul[data-v-a1fe05c0]{margin-left:30px}.stack-info>li ul li[data-v-a1fe05c0]{color:#fc5531;text-align:justify;margin:10px auto}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save