对接统一登录认证
This commit is contained in:
@@ -4,4 +4,5 @@ ENV = 'development'
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/dev-api'
|
||||
|
||||
VUE_APP_PROXY_API = 'https://www.yyds8848.com/ca/'
|
||||
# VUE_APP_PROXY_API = 'https://www.yyds8848.com/ca/'
|
||||
VUE_APP_PROXY_API = 'http://127.0.0.1:60000/'
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
"dependencies": {
|
||||
"axios": "1.8.2",
|
||||
"core-js": "^3.42.0",
|
||||
"echarts": "^5.6.0",
|
||||
"element-ui": "2.13.2",
|
||||
"js-cookie": "2.2.0",
|
||||
"js-sha256": "^0.11.1",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
|
||||
@@ -22,3 +22,11 @@ export function logout() {
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function callback(code) {
|
||||
return request({
|
||||
url: '/user/oauth/login/callback',
|
||||
method: 'get',
|
||||
params: { code }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,12 +8,11 @@ import getPageTitle from '@/utils/get-page-title'
|
||||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
|
||||
const whiteList = ['/login'] // no redirect whitelist
|
||||
const whiteList = ['/login', '/social', '/callback'] // no redirect whitelist
|
||||
|
||||
router.beforeEach(async(to, from, next) => {
|
||||
// start progress bar
|
||||
NProgress.start()
|
||||
|
||||
// set page title
|
||||
document.title = getPageTitle(to.meta.title)
|
||||
|
||||
@@ -46,7 +45,6 @@ router.beforeEach(async(to, from, next) => {
|
||||
}
|
||||
} else {
|
||||
/* has no token*/
|
||||
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
// in the free login whitelist, go directly
|
||||
next()
|
||||
|
||||
@@ -36,7 +36,15 @@ export const constantRoutes = [
|
||||
component: () => import('@/views/login/index'),
|
||||
hidden: true
|
||||
},
|
||||
|
||||
{
|
||||
path: '/social',
|
||||
component: () => import('@/views/login/social/index.vue'),
|
||||
hidden: true
|
||||
}, {
|
||||
path: '/callback',
|
||||
component: () => import('@/views/login/social/callback.vue'),
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import('@/views/404'),
|
||||
@@ -80,8 +88,8 @@ export const constantRoutes = [
|
||||
]
|
||||
|
||||
const createRouter = () => new Router({
|
||||
// mode: 'history', // require service support
|
||||
mode: 'hash',
|
||||
mode: 'history', // require service support
|
||||
// mode: 'hash',
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
routes: constantRoutes
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
|
||||
title: 'CA 证书签发平台',
|
||||
title: 'CA 证书签发管理系统',
|
||||
|
||||
/**
|
||||
* @type {boolean} true | false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { login, logout, getInfo } from '@/api/user'
|
||||
import { login, logout, getInfo, callback } from '@/api/user'
|
||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||
import { resetRouter } from '@/router'
|
||||
|
||||
@@ -33,9 +33,22 @@ const actions = {
|
||||
const { username, password } = userInfo
|
||||
return new Promise((resolve, reject) => {
|
||||
login({ username: username.trim(), password: password }).then(response => {
|
||||
const { data } = response
|
||||
commit('SET_TOKEN', data.token)
|
||||
setToken(data.token)
|
||||
const { access_token } = response.data
|
||||
commit('SET_TOKEN', access_token)
|
||||
setToken(access_token)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
callback({ commit }, code) {
|
||||
return new Promise((resolve, reject) => {
|
||||
callback(code).then(response => {
|
||||
const { access_token } = response.data
|
||||
commit('SET_TOKEN', access_token)
|
||||
setToken(access_token)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
|
||||
42
ca-admin-ui/src/utils/oauth-utils.js
Normal file
42
ca-admin-ui/src/utils/oauth-utils.js
Normal file
@@ -0,0 +1,42 @@
|
||||
// 使用 js-sha256 库
|
||||
import sha256 from 'js-sha256';
|
||||
|
||||
// 生成 code_verifier
|
||||
export function generateCodeVerifier() {
|
||||
const array = new Uint8Array(32);
|
||||
window.crypto.getRandomValues(array);
|
||||
return base64UrlEncode(array);
|
||||
}
|
||||
|
||||
// Base64 URL 编码
|
||||
function base64UrlEncode(uint8Array) {
|
||||
return btoa(String.fromCharCode.apply(null, uint8Array))
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/, '');
|
||||
}
|
||||
|
||||
// 使用 js-sha256 生成 code_challenge
|
||||
export function generateCodeChallenge(codeVerifier) {
|
||||
const hash = sha256.arrayBuffer(codeVerifier); // 返回 ArrayBuffer
|
||||
return base64UrlEncode(new Uint8Array(hash));
|
||||
}
|
||||
|
||||
// 构建授权 URL
|
||||
export function buildAuthorizeUrl(
|
||||
oauthServer,
|
||||
clientId,
|
||||
redirectUri,
|
||||
state,
|
||||
scope
|
||||
) {
|
||||
const params = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
client_id: clientId,
|
||||
redirect_uri: redirectUri,
|
||||
scope,
|
||||
state,
|
||||
});
|
||||
|
||||
return `${oauthServer}/oauth2/authorize?${params.toString()}`;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<el-card class="chart-card" shadow="hover">
|
||||
<div slot="header" class="chart-header">
|
||||
<span>订单分布</span>
|
||||
<el-select v-model="chartType" size="small" @change="handleTypeChange">
|
||||
<el-option label="按平台" value="platform" />
|
||||
<el-option label="按地区" value="region" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div ref="chart" class="chart-content" />
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
export default {
|
||||
name: 'OrderDistributionChart',
|
||||
data() {
|
||||
return {
|
||||
chartType: 'platform',
|
||||
chart: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
if (this.chart) {
|
||||
this.chart.dispose()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
this.chart = echarts.init(this.$refs.chart)
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: {
|
||||
color: '#606266'
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: '订单来源',
|
||||
type: 'pie',
|
||||
radius: ['50%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '18',
|
||||
fontWeight: 'bold',
|
||||
formatter: '{b}\n{c} ({d}%)'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 335, name: '平台A', itemStyle: { color: '#409EFF' }},
|
||||
{ value: 310, name: '平台B', itemStyle: { color: '#67C23A' }},
|
||||
{ value: 274, name: '平台C', itemStyle: { color: '#E6A23C' }},
|
||||
{ value: 235, name: '平台D', itemStyle: { color: '#F56C6C' }},
|
||||
{ value: 400, name: '平台E', itemStyle: { color: '#9C27B0' }}
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
this.chart.setOption(option)
|
||||
},
|
||||
handleResize() {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
},
|
||||
handleTypeChange() {
|
||||
// 实际项目中可以在这里触发数据更新
|
||||
// this.$emit('type-change', this.chartType)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chart-card {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
|
||||
.chart-header {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
height: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.chart-card {
|
||||
.chart-content {
|
||||
height: 250px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
239
ca-admin-ui/src/views/dashboard/components/QuickActions.vue
Normal file
239
ca-admin-ui/src/views/dashboard/components/QuickActions.vue
Normal file
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<el-row :gutter="20" class="quick-actions-container">
|
||||
<!-- Left Column - Project Info -->
|
||||
<el-col :xs="24" :md="18" class="project-info-col">
|
||||
<el-row :gutter="20" class="projects-container">
|
||||
<el-col v-for="(project, idx) in projects.slice(0, 12)" :key="idx" :xs="24" :sm="6">
|
||||
<el-card
|
||||
shadow="hover"
|
||||
class="project-info-card"
|
||||
style="cursor: pointer;"
|
||||
@click.native="openProject(project.url)"
|
||||
>
|
||||
<div class="project-info">
|
||||
<div class="project-icon">
|
||||
<i :class="['el-icon-' + project.icon]" />
|
||||
</div>
|
||||
<div class="project-details">
|
||||
<h3 class="project-name">{{ project.name }}</h3>
|
||||
<p class="project-description">{{ project.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
|
||||
<!-- Right Column - Action Matrix -->
|
||||
<el-col :xs="24" :md="6" class="action-matrix-col">
|
||||
<el-row :gutter="16" class="action-matrix">
|
||||
<el-col
|
||||
v-for="(action, idx) in actions"
|
||||
:key="idx"
|
||||
:xs="8"
|
||||
:sm="8"
|
||||
class="action-cell"
|
||||
>
|
||||
<div class="matrix-action-item" @click="handleActionClick(action.path)">
|
||||
<div class="matrix-action-icon" :style="{ backgroundColor: action.color }">
|
||||
<i :class="['btn-icon', action.icon]" />
|
||||
</div>
|
||||
<span class="matrix-action-label">{{ action.label }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'QuickActions',
|
||||
props: {
|
||||
projects: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
actions: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleActionClick(path) {
|
||||
this.$emit('action-click', path)
|
||||
},
|
||||
openProject(url) {
|
||||
window.open(url, '_blank') // 新标签页打开项目链接
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>.quick-actions-container {
|
||||
|
||||
.project-info-col {
|
||||
.projects-container {
|
||||
.project-info-card {
|
||||
height: 140px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px; // 略微减少底部间距
|
||||
|
||||
.project-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px; // 减少内边距
|
||||
|
||||
.project-icon {
|
||||
width: 40px; // 缩小图标容器
|
||||
height: 40px;
|
||||
border-radius: 10px; // 略微减少圆角半径
|
||||
background-color: #409EFF20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px; // 减少右边距
|
||||
flex-shrink: 0;
|
||||
|
||||
i {
|
||||
font-size: 20px; // 缩小图标字体大小
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
.project-details {
|
||||
flex: 1;
|
||||
|
||||
.project-name {
|
||||
margin: 0 0 6px 0; // 调整间距
|
||||
color: #303133;
|
||||
font-size: 16px; // 略微减小字体大小
|
||||
}
|
||||
|
||||
.project-description {
|
||||
margin: 0;
|
||||
color: #909399;
|
||||
font-size: 12px; // 减小字体大小
|
||||
line-height: 1.4; // 略微减少行高
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-matrix-col {
|
||||
.action-matrix {
|
||||
height: 100%;
|
||||
|
||||
.action-cell {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.matrix-action-item {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 10px 7px; // 减少内边距
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
border: 1px solid #ebeef5;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
border-color: #409EFF;
|
||||
|
||||
.matrix-action-icon {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.matrix-action-icon {
|
||||
width: 25px; // 略微缩小图标容器
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 5px; // 减少底部间距
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.btn-icon {
|
||||
font-size: 18px; // 缩小图标字体大小
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.matrix-action-label {
|
||||
display: block;
|
||||
font-size: 11px; // 减小字体大小
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.quick-actions-container {
|
||||
.project-info-col {
|
||||
.projects-container {
|
||||
.project-info-card {
|
||||
padding: 8px; // 进一步减少内边距
|
||||
|
||||
.project-icon {
|
||||
width: 36px; // 移动端进一步缩小图标
|
||||
height: 36px;
|
||||
|
||||
i {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-details {
|
||||
.project-name {
|
||||
font-size: 14px; // 移动端字体更小
|
||||
}
|
||||
|
||||
.project-description {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-matrix-col {
|
||||
.action-matrix {
|
||||
.action-cell {
|
||||
.matrix-action-item {
|
||||
padding: 8px 4px; // 减少内边距
|
||||
|
||||
.matrix-action-icon {
|
||||
width: 32px; // 移动端进一步缩小图标
|
||||
height: 32px;
|
||||
|
||||
.btn-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.matrix-action-label {
|
||||
font-size: 10px; // 更小的字体大小
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
76
ca-admin-ui/src/views/dashboard/components/RecentOrders.vue
Normal file
76
ca-admin-ui/src/views/dashboard/components/RecentOrders.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<el-card class="order-card" shadow="hover">
|
||||
<div slot="header" class="order-header">
|
||||
<span>最新订单</span>
|
||||
<el-button type="text" @click="handleViewMore">查看更多</el-button>
|
||||
</div>
|
||||
<el-table :data="orders" style="width: 100%" class="order-table">
|
||||
<el-table-column prop="id" label="订单号" width="120" />
|
||||
<el-table-column prop="customer" label="客户" width="120" />
|
||||
<el-table-column prop="product" label="产品" />
|
||||
<el-table-column prop="amount" label="金额" width="120">
|
||||
<template #scope>
|
||||
<span style="color: #F56C6C; font-weight: bold;">¥{{ scope.row.amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="120">
|
||||
<template #scope>
|
||||
<el-tag :type="getStatusTagType(scope.row.status)" size="small">
|
||||
{{ scope.row.status }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80">
|
||||
<template #scope>
|
||||
<el-button type="text" size="small" @click="handleViewDetail(scope.row)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'RecentOrders',
|
||||
props: {
|
||||
orders: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getStatusTagType(status) {
|
||||
const map = {
|
||||
'已完成': 'success',
|
||||
'处理中': 'primary',
|
||||
'已发货': 'warning',
|
||||
'待付款': 'danger'
|
||||
}
|
||||
return map[status] || 'info'
|
||||
},
|
||||
handleViewDetail(order) {
|
||||
this.$emit('view-detail', order)
|
||||
},
|
||||
handleViewMore() {
|
||||
this.$emit('view-more')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.order-card {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
149
ca-admin-ui/src/views/dashboard/components/SalesTrendChart.vue
Normal file
149
ca-admin-ui/src/views/dashboard/components/SalesTrendChart.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<el-card class="chart-card" shadow="hover">
|
||||
<div slot="header" class="chart-header">
|
||||
<span>销售趋势图</span>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
size="small"
|
||||
placeholder="选择日期范围"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
</div>
|
||||
<div ref="chart" class="chart-content" />
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
export default {
|
||||
name: 'SalesTrendChart',
|
||||
data() {
|
||||
return {
|
||||
dateRange: [new Date(2023, 0, 1), new Date(2023, 6, 1)],
|
||||
chart: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
if (this.chart) {
|
||||
this.chart.dispose()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
this.chart = echarts.init(this.$refs.chart)
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: '{b}<br/>{a0}: {c0}元',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#DCDFE6'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#606266'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#606266',
|
||||
formatter: '{value}元'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: ['#EBEEF5'],
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: '销售额',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [12000, 15000, 13000, 18000, 20000, 25000, 22000],
|
||||
itemStyle: {
|
||||
color: '#409EFF'
|
||||
},
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(64, 158, 255, 0.5)' },
|
||||
{ offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
|
||||
])
|
||||
},
|
||||
symbolSize: 8,
|
||||
lineStyle: {
|
||||
width: 3
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
this.chart.setOption(option)
|
||||
},
|
||||
handleResize() {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
},
|
||||
handleDateChange() {
|
||||
// 实际项目中可以在这里触发数据更新
|
||||
// this.$emit('date-change', this.dateRange)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chart-card {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
|
||||
.chart-header {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
height: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.chart-card {
|
||||
.chart-content {
|
||||
height: 250px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
247
ca-admin-ui/src/views/dashboard/components/StatCards.vue
Normal file
247
ca-admin-ui/src/views/dashboard/components/StatCards.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<el-row :gutter="20" class="stat-row">
|
||||
<el-col v-for="(item, index) in statsList" :key="index" :xs="24" :sm="12" :md="6">
|
||||
<el-card class="stat-card" shadow="hover">
|
||||
<transition name="fade">
|
||||
<div :key="item.value" class="stat-content">
|
||||
<div class="icon-wrapper" :style="{ backgroundColor: item.color + '20' }">
|
||||
<i :class="['icon', item.icon]" :style="{ color: item.color }" />
|
||||
</div>
|
||||
<div class="stat-text">
|
||||
<p class="label">{{ item.label }}</p>
|
||||
<h3 class="value">{{ formattedValues[index] }}</h3>
|
||||
<div v-if="item.trend" class="trend">
|
||||
<i
|
||||
:class="['el-icon-' + (item.trend > 0 ? 'top' : 'bottom')]"
|
||||
:style="{ color: item.trend > 0 ? '#67C23A' : '#F56C6C' }"
|
||||
/>
|
||||
<span :style="{ color: item.trend > 0 ? '#67C23A' : '#F56C6C' }">
|
||||
{{ Math.abs(item.trend) }}%
|
||||
</span>
|
||||
<span class="period">较上月</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'StatCards',
|
||||
props: {
|
||||
statsList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
animatedValues: [],
|
||||
formattedValues: [],
|
||||
animationFrames: {} // Initialize animationFrames here
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
statsList: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
// Initialize arrays with proper length
|
||||
this.animatedValues = new Array(newVal.length).fill(0)
|
||||
this.formattedValues = new Array(newVal.length).fill('')
|
||||
|
||||
newVal.forEach((item, index) => {
|
||||
this.startAnimation(index, item)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
// Safely cancel all animations
|
||||
if (this.animationFrames) {
|
||||
Object.keys(this.animationFrames).forEach(index => {
|
||||
cancelAnimationFrame(this.animationFrames[index])
|
||||
})
|
||||
// 清除数组引用
|
||||
this.animatedValues = []
|
||||
this.formattedValues = []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
extractNumber(value) {
|
||||
if (value === null || value === undefined) return 0
|
||||
const match = String(value).match(/\d+\.?\d*/)
|
||||
return match ? parseFloat(match[0]) : 0
|
||||
},
|
||||
|
||||
formatNumber(num, prefix = '') {
|
||||
if (isNaN(num)) return prefix + '0'
|
||||
return prefix + Math.floor(num).toLocaleString()
|
||||
},
|
||||
|
||||
getValuePrefix(originalValue) {
|
||||
if (!originalValue) return ''
|
||||
const strVal = String(originalValue)
|
||||
if (strVal.includes('¥')) return '¥'
|
||||
if (strVal.includes('$')) return '$'
|
||||
return ''
|
||||
},
|
||||
|
||||
startAnimation(index, item) {
|
||||
// Add null checks
|
||||
if (!item || item.value === undefined) {
|
||||
this.formattedValues[index] = ''
|
||||
return
|
||||
}
|
||||
|
||||
const targetValue = this.extractNumber(item.value)
|
||||
const prefix = this.getValuePrefix(item.value)
|
||||
|
||||
// Check if animationFrames exists and has the index
|
||||
if (this.animationFrames && this.animationFrames[index] !== undefined) {
|
||||
cancelAnimationFrame(this.animationFrames[index])
|
||||
}
|
||||
|
||||
this.animateValue(index, targetValue, prefix)
|
||||
},
|
||||
|
||||
animateValue(index, targetValue, prefix) {
|
||||
const duration = 1000
|
||||
const startTime = performance.now()
|
||||
const startValue = 0
|
||||
|
||||
const animate = (timestamp) => {
|
||||
const elapsed = timestamp - startTime
|
||||
const progress = Math.min(elapsed / duration, 1)
|
||||
const currentValue = Math.floor(progress * (targetValue - startValue) + startValue)
|
||||
|
||||
// Use Vue.set for arrays to ensure reactivity
|
||||
this.$set(this.animatedValues, index, currentValue)
|
||||
this.$set(this.formattedValues, index, this.formatNumber(currentValue, prefix))
|
||||
|
||||
if (progress < 1) {
|
||||
this.$set(this.animationFrames, index, requestAnimationFrame(animate))
|
||||
} else {
|
||||
// Ensure final values are set
|
||||
this.$set(this.animatedValues, index, targetValue)
|
||||
this.$set(this.formattedValues, index, this.formatNumber(targetValue, prefix))
|
||||
this.$delete(this.animationFrames, index)
|
||||
}
|
||||
}
|
||||
|
||||
this.$set(this.animationFrames, index, requestAnimationFrame(animate))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.stat-row {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.stat-card {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
|
||||
.icon-wrapper {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-text {
|
||||
flex: 1;
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
margin: 0 0 5px 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 22px;
|
||||
color: #303133;
|
||||
margin: 0 0 8px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.trend {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
|
||||
i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.period {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.stat-row {
|
||||
.stat-card {
|
||||
.stat-content {
|
||||
padding: 12px;
|
||||
|
||||
.icon-wrapper {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 12px;
|
||||
|
||||
.icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-text {
|
||||
.value {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 动画过渡效果 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,30 +1,136 @@
|
||||
<template>
|
||||
<div class="dashboard-container">
|
||||
<div class="dashboard-text">name: {{ name }}</div>
|
||||
<!-- 数据统计卡片 -->
|
||||
<stat-cards :stats-list="statsList" />
|
||||
|
||||
<!-- 快捷操作矩阵 -->
|
||||
<!-- <quick-actions-->
|
||||
<!-- :projects="projects"-->
|
||||
<!-- :actions="actions"-->
|
||||
<!-- @action-click="goTo"-->
|
||||
<!-- />-->
|
||||
<!-- 图表区 -->
|
||||
<el-row :gutter="20" class="chart-row">
|
||||
<el-col :xs="24" :md="16">
|
||||
<sales-trend-chart />
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="8">
|
||||
<order-distribution-chart />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 最新订单 -->
|
||||
<recent-orders
|
||||
:orders="recentOrders"
|
||||
@view-detail="viewOrder"
|
||||
@view-more="goTo('/orders')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import StatCards from './components/StatCards.vue'
|
||||
import QuickActions from './components/QuickActions.vue'
|
||||
import SalesTrendChart from './components/SalesTrendChart.vue'
|
||||
import OrderDistributionChart from './components/OrderDistributionChart.vue'
|
||||
import RecentOrders from './components/RecentOrders.vue'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'name'
|
||||
])
|
||||
components: {
|
||||
StatCards,
|
||||
QuickActions,
|
||||
SalesTrendChart,
|
||||
OrderDistributionChart,
|
||||
RecentOrders
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statsList: [
|
||||
{
|
||||
label: '总用户数',
|
||||
value: '42345',
|
||||
icon: 'el-icon-user-solid',
|
||||
color: '#409EFF',
|
||||
trend: 12.5
|
||||
},
|
||||
{
|
||||
label: '总订单数',
|
||||
value: '890',
|
||||
icon: 'el-icon-tickets',
|
||||
color: '#F56C6C',
|
||||
trend: 8.2
|
||||
},
|
||||
{
|
||||
label: '本月销售额',
|
||||
value: '¥78900',
|
||||
icon: 'el-icon-money',
|
||||
color: '#67C23A',
|
||||
trend: -2.4
|
||||
},
|
||||
{
|
||||
label: '商品总数',
|
||||
value: '234',
|
||||
icon: 'el-icon-s-goods',
|
||||
color: '#E6A23C',
|
||||
trend: 5.6
|
||||
}
|
||||
],
|
||||
projects: [
|
||||
{ name: '天维服务管理系统', description: 'Version 2.1.0', icon: 'office-building', url: 'http://localhost:8080' },
|
||||
{ name: '星璇网关管理系统', description: 'Version 2.1.0', icon: 'office-building', url: 'http://localhost:8081' },
|
||||
{ name: '数据融合业务中台', description: 'Version 2.1.0', icon: 'office-building', url: 'http://localhost:8082' },
|
||||
{ name: '统一身份认证登录', description: 'Version 2.1.0', icon: 'office-building', url: 'http://localhost:8083' }
|
||||
|
||||
],
|
||||
actions: [
|
||||
{ label: '用户管理', icon: 'el-icon-user', path: '/users', color: '#409EFF' },
|
||||
{ label: '订单管理', icon: 'el-icon-tickets', path: '/orders', color: '#F56C6C' },
|
||||
{ label: '商品管理', icon: 'el-icon-s-goods', path: '/products', color: '#E6A23C' },
|
||||
{ label: '库存管理', icon: 'el-icon-box', path: '/inventory', color: '#909399' },
|
||||
{ label: '数据报表', icon: 'el-icon-data-line', path: '/reports', color: '#67C23A' },
|
||||
{ label: '系统设置', icon: 'el-icon-setting', path: '/settings', color: '#9C27B0' }
|
||||
],
|
||||
recentOrders: [
|
||||
{ id: 'A001', customer: '张三', product: 'iPhone 13 Pro', amount: 8999, status: '已完成', date: '2023-05-12' },
|
||||
{ id: 'A002', customer: '李四', product: 'MacBook Pro', amount: 12999, status: '处理中', date: '2023-05-11' },
|
||||
{ id: 'A003', customer: '王五', product: 'AirPods Pro', amount: 1499, status: '已完成', date: '2023-05-10' },
|
||||
{ id: 'A004', customer: '赵六', product: 'iPad Air', amount: 4399, status: '已发货', date: '2023-05-09' },
|
||||
{ id: 'A004', customer: '赵六', product: 'iPad Air', amount: 4399, status: '已发货', date: '2023-05-09' },
|
||||
{ id: 'A004', customer: '赵六', product: 'iPad Air', amount: 4399, status: '已发货', date: '2023-05-09' },
|
||||
{ id: 'A005', customer: '钱七', product: 'Apple Watch', amount: 2999, status: '待付款', date: '2023-05-08' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goTo(path) {
|
||||
this.$router.push(path)
|
||||
},
|
||||
viewOrder(order) {
|
||||
this.$message.success(`查看订单: ${order.id}`)
|
||||
// 实际项目中可以跳转到订单详情页
|
||||
// this.$router.push(`/orders/detail/${order.id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard {
|
||||
&-container {
|
||||
margin: 30px;
|
||||
}
|
||||
&-text {
|
||||
font-size: 30px;
|
||||
line-height: 46px;
|
||||
.dashboard-container {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
min-height: calc(100vh - 84px);
|
||||
}
|
||||
|
||||
.chart-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.chart-row {
|
||||
.el-col {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<template>
|
||||
<div class="login-container">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
|
||||
<el-form
|
||||
ref="loginForm"
|
||||
:model="loginForm"
|
||||
:rules="loginRules"
|
||||
class="login-form"
|
||||
auto-complete="on"
|
||||
label-position="left"
|
||||
>
|
||||
<transition name="fade">
|
||||
<div class="title-container">
|
||||
<h3 class="title">CA 证书签发平台</h3>
|
||||
<h3 class="title">CA 证书签发管理系统</h3>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
@@ -14,7 +21,7 @@
|
||||
<el-input
|
||||
ref="username"
|
||||
v-model="loginForm.username"
|
||||
placeholder="用户名 / 邮箱 / 手机号"
|
||||
placeholder="用户名/邮箱/手机号"
|
||||
name="username"
|
||||
type="text"
|
||||
tabindex="1"
|
||||
@@ -42,11 +49,47 @@
|
||||
</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button>
|
||||
<!-- 新增:验证码 -->
|
||||
<!-- <el-form-item prop="captcha">-->
|
||||
<!-- <span class="svg-container">-->
|
||||
<!-- <svg-icon icon-class="validCode" />-->
|
||||
<!-- </span>-->
|
||||
<!-- <el-input-->
|
||||
<!-- v-model="loginForm.captcha"-->
|
||||
<!-- placeholder="验证码"-->
|
||||
<!-- name="captcha"-->
|
||||
<!-- style="width: 60%; display: inline-block"-->
|
||||
<!-- tabindex="3"-->
|
||||
<!-- />-->
|
||||
<!-- <!– <img :src="captchaUrl" alt="验证码" class="captcha-img" @click="refreshCaptcha" />–>-->
|
||||
<!-- </el-form-item>-->
|
||||
|
||||
<!-- 新增:“记住我”选项 -->
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin-bottom: 20px;">记住我</el-checkbox>
|
||||
<div>
|
||||
<div>
|
||||
|
||||
<el-button
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
style="width:100%;margin-bottom:30px;"
|
||||
@click.native.prevent="handleLogin"
|
||||
>登录
|
||||
</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
style="width:100%;margin-bottom:30px;"
|
||||
@click.native.prevent="handleOauthLogin"
|
||||
>统一认证登录
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { validUsername } from '@/utils/validate'
|
||||
|
||||
@@ -67,10 +110,13 @@ export default {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loginForm: {
|
||||
username: 'admin',
|
||||
password: 'yyds@8848'
|
||||
username: '',
|
||||
password: '',
|
||||
captcha: '',
|
||||
rememberMe: false
|
||||
},
|
||||
loginRules: {
|
||||
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
|
||||
@@ -78,7 +124,8 @@ export default {
|
||||
},
|
||||
loading: false,
|
||||
passwordType: 'password',
|
||||
redirect: undefined
|
||||
redirect: undefined,
|
||||
captchaUrl: '/api/captcha?timestamp=' + new Date().getTime() // 示例 URL
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -89,6 +136,16 @@ export default {
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 页面加载时检查是否已保存过信息
|
||||
const remembered = localStorage.getItem('rememberedUser')
|
||||
if (remembered) {
|
||||
const user = JSON.parse(remembered)
|
||||
this.loginForm.username = user.username
|
||||
this.loginForm.password = user.password
|
||||
this.loginForm.rememberMe = true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showPwd() {
|
||||
if (this.passwordType === 'password') {
|
||||
@@ -100,15 +157,31 @@ export default {
|
||||
this.$refs.password.focus()
|
||||
})
|
||||
},
|
||||
refreshCaptcha() {
|
||||
this.captchaUrl = '/api/captcha?timestamp=' + new Date().getTime()
|
||||
},
|
||||
handleOauthLogin() {
|
||||
this.$router.push({ path: '/social' })
|
||||
},
|
||||
handleLogin() {
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
|
||||
// 如果用户勾选了“记住我”,保存账号密码到 localStorage
|
||||
if (this.loginForm.rememberMe) {
|
||||
localStorage.setItem('rememberedUser', JSON.stringify({
|
||||
username: this.loginForm.username,
|
||||
password: this.loginForm.password
|
||||
}))
|
||||
}
|
||||
|
||||
this.$store.dispatch('user/login', this.loginForm).then(() => {
|
||||
this.$router.push({ path: this.redirect || '/' })
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
this.refreshCaptcha()
|
||||
})
|
||||
} else {
|
||||
console.log('error submit!!')
|
||||
@@ -118,14 +191,15 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* 修复input 背景不协调 和光标变色 */
|
||||
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
|
||||
|
||||
$bg:#283443;
|
||||
$light_gray:#fff;
|
||||
$bg: #283443;
|
||||
$light_gray: #fff;
|
||||
$cursor: #fff;
|
||||
|
||||
@supports (-webkit-mask: none) and (not (caret-color: $cursor)) {
|
||||
@@ -143,16 +217,17 @@ $cursor: #fff;
|
||||
|
||||
input {
|
||||
background: transparent;
|
||||
border: 0px;
|
||||
border: 0;
|
||||
-webkit-appearance: none;
|
||||
border-radius: 0px;
|
||||
appearance: none; // 新增标准属性
|
||||
border-radius: 0;
|
||||
padding: 12px 5px 12px 15px;
|
||||
color: $light_gray;
|
||||
height: 47px;
|
||||
caret-color: $cursor;
|
||||
|
||||
&:-webkit-autofill {
|
||||
box-shadow: 0 0 0px 1000px $bg inset !important;
|
||||
box-shadow: 0 0 0 1000px $bg inset !important;
|
||||
-webkit-text-fill-color: $cursor !important;
|
||||
}
|
||||
}
|
||||
@@ -169,8 +244,8 @@ $cursor: #fff;
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$bg: linear-gradient(135deg, #1e3c72, #2a5298); // 渐变蓝背景
|
||||
$dark_gray:#666;
|
||||
$light_gray:#fff;
|
||||
$dark_gray: #666;
|
||||
$light_gray: #fff;
|
||||
|
||||
.login-container {
|
||||
min-height: 100%;
|
||||
@@ -246,10 +321,27 @@ $light_gray:#fff;
|
||||
}
|
||||
}
|
||||
|
||||
.captcha-img {
|
||||
width: 90px;
|
||||
height: 40px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
// 可以给验证码区域加点样式
|
||||
.el-form-item__content .svg-container {
|
||||
width: 30px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
// 过渡动画
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
28
ca-admin-ui/src/views/login/social/callback.vue
Normal file
28
ca-admin-ui/src/views/login/social/callback.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
this.handleGetAccessToken()
|
||||
},
|
||||
methods: {
|
||||
handleGetAccessToken() {
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const authorizationCode = urlParams.get('code')
|
||||
const state = urlParams.get('state')
|
||||
console.log(authorizationCode)
|
||||
this.$store.dispatch('user/callback', authorizationCode).then(() => {
|
||||
this.$router.push({ path: this.redirect || '/' })
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
this.refreshCaptcha()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
28
ca-admin-ui/src/views/login/social/index.vue
Normal file
28
ca-admin-ui/src/views/login/social/index.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<script>
|
||||
import { buildAuthorizeUrl } from '@/utils/oauth-utils'
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
this.handleAuthorize()
|
||||
},
|
||||
methods: {
|
||||
handleAuthorize() {
|
||||
const authUrl = buildAuthorizeUrl(
|
||||
'http://127.0.0.1:8080',
|
||||
'certificate-authority-client',
|
||||
'http://127.0.0.1:9529/callback',
|
||||
'',
|
||||
'openid profile certificate.read certificate.write'
|
||||
)
|
||||
console.log(authUrl)
|
||||
debugger
|
||||
// 跳转授权页面(可选)
|
||||
window.location.href = authUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -6,14 +6,14 @@ function resolve(dir) {
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
const name = defaultSettings.title || 'CA 证书签发平台 ' // page title
|
||||
const name = defaultSettings.title || 'CA 证书签发管理系统 ' // page title
|
||||
|
||||
// If your port is set to 80,
|
||||
// use administrator privileges to execute the command line.
|
||||
// For example, Mac: sudo npm run
|
||||
// You can change the port by the following methods:
|
||||
// port = 9528 npm run dev OR npm run dev --port = 9528
|
||||
const port = process.env.port || process.env.npm_config_port || 9528 // dev port
|
||||
const port = process.env.port || process.env.npm_config_port || 9529 // dev port
|
||||
|
||||
// All configuration item explanations can be find in https://cli.vuejs.org/config/
|
||||
module.exports = {
|
||||
@@ -24,7 +24,8 @@ module.exports = {
|
||||
* In most cases please use '/' !!!
|
||||
* Detail: https://cli.vuejs.org/config/#publicpath
|
||||
*/
|
||||
publicPath: '/ca-admin',
|
||||
// publicPath: '/ca-admin',
|
||||
publicPath: '/',
|
||||
outputDir: 'dist',
|
||||
assetsDir: 'static',
|
||||
lintOnSave: process.env.NODE_ENV === 'development',
|
||||
@@ -36,7 +37,7 @@ module.exports = {
|
||||
warnings: false,
|
||||
errors: true
|
||||
},
|
||||
before: require('./mock/mock-server.js'),
|
||||
// before: require('./mock/mock-server.js'),
|
||||
proxy: {
|
||||
[process.env.VUE_APP_BASE_API]: {
|
||||
target: process.env.VUE_APP_PROXY_API,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ logging:
|
||||
# 日志级别
|
||||
level: debug
|
||||
# 日志文件路径
|
||||
path: /home/code/git/ca-mini/ca-server/logs
|
||||
path: ./logs
|
||||
|
||||
datasource:
|
||||
# 数据源配置
|
||||
@@ -28,4 +28,21 @@ datasource:
|
||||
# 数据库用户名
|
||||
username: root
|
||||
# 数据库密码
|
||||
password: yyds@8848
|
||||
password: yyds@8848
|
||||
|
||||
|
||||
|
||||
|
||||
# OAuth2 配置部分
|
||||
oauth:
|
||||
# 授权服务器的地址
|
||||
authorization_server_host: "http://127.0.0.1:8080"
|
||||
# 客户端 ID,用于标识客户端应用
|
||||
client_id: "certificate-authority-client"
|
||||
# 客户端密钥,用于认证客户端身份
|
||||
client_secret: "certificate-authority-secret"
|
||||
# 回调地址,授权完成后重定向的目标地址
|
||||
redirect_uri: "http://127.0.0.1:9529/callback"
|
||||
# 获取令牌的 URL 路径(通常位于授权服务器下)
|
||||
token_url: "/oauth2/token"
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ go 1.23.4
|
||||
|
||||
require (
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/go-sql-driver/mysql v1.9.2
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/viper v1.20.1
|
||||
@@ -12,9 +13,7 @@ require (
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
|
||||
@@ -15,8 +15,6 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
|
||||
@@ -29,11 +29,21 @@ type DatasourceConfig struct {
|
||||
Password string `mapstructure:"password"`
|
||||
}
|
||||
|
||||
// 定义 OAuth 配置结构体
|
||||
type OAuthConfig struct {
|
||||
AUTHORIZATION_SERVER_HOST string `yaml:"authorization_server_host"`
|
||||
CLIENT_ID string `yaml:"client_id"`
|
||||
CLIENT_SECRET string `yaml:"client_secret"`
|
||||
REDIRECT_URI string `yaml:"redirect_uri"`
|
||||
TOKEN_URL string `yaml:"token_url"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
App AppConfig `mapstructure:"app"`
|
||||
Server ServerConfig `mapstructure:"server"`
|
||||
Datasource DatasourceConfig `mapstructure:"datasource"`
|
||||
Logging LoggingConfig `mapstructure:"logging"`
|
||||
OAuth OAuthConfig `mapstructure:"oauth"`
|
||||
ServerAddress string
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"ca-mini/internal/config"
|
||||
"ca-mini/pkg/utils"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -14,7 +21,7 @@ type LoginRequest struct {
|
||||
}
|
||||
|
||||
type TokenInfo struct {
|
||||
Token string `json:"token"`
|
||||
Token string `json:"access_token"`
|
||||
}
|
||||
|
||||
type UserInfo struct {
|
||||
@@ -42,6 +49,21 @@ type UserInfoResponse struct {
|
||||
Data UserInfo `json:"data"`
|
||||
}
|
||||
|
||||
// Token 是返回的 Token 结构体
|
||||
type Token struct {
|
||||
TokenType string `json:"token_type,omitempty"`
|
||||
ExpiresIn int64 `json:"expires_in,omitempty"`
|
||||
AccessToken string `json:"access_token,omitempty"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
}
|
||||
|
||||
type TokenResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Date string `json:"date"`
|
||||
Data Token `json:"data"`
|
||||
}
|
||||
|
||||
// IssueCertificate 处理证书签发请求
|
||||
func Login(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -114,3 +136,88 @@ func GetUserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func AuthCallBack(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load oauth config: %v", err)
|
||||
}
|
||||
|
||||
// 从 URL 中提取 authorization code
|
||||
code := r.URL.Query().Get("code")
|
||||
if code == "" {
|
||||
http.Error(w, "Missing authorization code", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 构造 Basic Auth header
|
||||
auth := cfg.OAuth.CLIENT_ID + ":" + cfg.OAuth.CLIENT_SECRET
|
||||
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
|
||||
|
||||
// 构造请求体
|
||||
formData := url.Values{}
|
||||
formData.Add("grant_type", "authorization_code")
|
||||
formData.Add("redirect_uri", cfg.OAuth.REDIRECT_URI)
|
||||
formData.Add("client_id", cfg.OAuth.CLIENT_ID)
|
||||
formData.Add("code", code)
|
||||
|
||||
// 创建请求
|
||||
tokenURL := cfg.OAuth.AUTHORIZATION_SERVER_HOST + cfg.OAuth.TOKEN_URL
|
||||
req, err := http.NewRequestWithContext(context.Background(), "POST", tokenURL, bytes.NewBufferString(formData.Encode()))
|
||||
if err != nil {
|
||||
log.Printf("Error creating request: %v", err)
|
||||
http.Error(w, "Failed to create token request", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("Unexpected error while fetching token: %v", err)
|
||||
http.Error(w, "Failed to fetch token", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Error reading response body: %v", err)
|
||||
http.Error(w, "Failed to read token response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("Error while fetching token: %s, response body: %s", resp.Status, body)
|
||||
http.Error(w, fmt.Sprintf("Token request failed: %s", resp.Status), resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析 JSON 到 Token 结构体
|
||||
var token Token
|
||||
if err := json.Unmarshal(body, &token); err != nil {
|
||||
log.Printf("Error unmarshalling token response: %v", err)
|
||||
http.Error(w, "Failed to parse token response", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// 返回 Token 信息
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
response := TokenResponse{
|
||||
Code: http.StatusOK,
|
||||
Message: "Login successful",
|
||||
Date: time.Now().Format(time.RFC3339),
|
||||
Data: token,
|
||||
}
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
log.Printf("Error encoding JSON response: %v", err)
|
||||
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ func SetupAPIRoutes(r *mux.Router) {
|
||||
r.HandleFunc("/user/login", handlers.Login).Methods("POST")
|
||||
r.HandleFunc("/user/logout", handlers.Logout).Methods("POST")
|
||||
r.HandleFunc("/user/info", handlers.GetUserInfo).Methods("GET")
|
||||
r.HandleFunc("/user/oauth/login/callback", handlers.AuthCallBack).Methods("GET")
|
||||
|
||||
api := r.PathPrefix("/api/v1").Subrouter()
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
const (
|
||||
OPENSSL_PATH = "openssl"
|
||||
// WORK_PATH = "/opt/arrokoth/ca-mini"
|
||||
WORK_PATH = "/home/code/git/ca-mini/ca-server"
|
||||
WORK_PATH = "/Users/seven/arrokoth/sample-demo/certificate-management/ca-server"
|
||||
CA_CERT = WORK_PATH + "/ca/CaRoot.crt"
|
||||
CA_CONFIG = WORK_PATH + "/ca/ca.conf"
|
||||
CERT_PATH = WORK_PATH + "/cert"
|
||||
|
||||
41
ca-server/vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
41
ca-server/vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
@@ -1,41 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06))
|
||||
* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6))
|
||||
|
||||
## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29))
|
||||
|
||||
## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4))
|
||||
|
||||
### Fixes
|
||||
|
||||
* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior)
|
||||
|
||||
## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0))
|
||||
|
||||
## Changelog
|
||||
26
ca-server/vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
26
ca-server/vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
@@ -1,26 +0,0 @@
|
||||
# How to contribute
|
||||
|
||||
We definitely welcome patches and contribution to this project!
|
||||
|
||||
### Tips
|
||||
|
||||
Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org).
|
||||
|
||||
Always try to include a test case! If it is not possible or not necessary,
|
||||
please explain why in the pull request description.
|
||||
|
||||
### Releasing
|
||||
|
||||
Commits that would precipitate a SemVer change, as described in the Conventional
|
||||
Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action)
|
||||
to create a release candidate pull request. Once submitted, `release-please`
|
||||
will create a release.
|
||||
|
||||
For tips on how to work with `release-please`, see its documentation.
|
||||
|
||||
### Legal requirements
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||
|
||||
You may have already signed it for other Google projects.
|
||||
9
ca-server/vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
9
ca-server/vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
@@ -1,9 +0,0 @@
|
||||
Paul Borman <borman@google.com>
|
||||
bmatsuo
|
||||
shawnps
|
||||
theory
|
||||
jboverfelt
|
||||
dsymonds
|
||||
cd1
|
||||
wallclockbuilder
|
||||
dansouza
|
||||
27
ca-server/vendor/github.com/google/uuid/LICENSE
generated
vendored
27
ca-server/vendor/github.com/google/uuid/LICENSE
generated
vendored
@@ -1,27 +0,0 @@
|
||||
Copyright (c) 2009,2014 Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
21
ca-server/vendor/github.com/google/uuid/README.md
generated
vendored
21
ca-server/vendor/github.com/google/uuid/README.md
generated
vendored
@@ -1,21 +0,0 @@
|
||||
# uuid
|
||||
The uuid package generates and inspects UUIDs based on
|
||||
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
|
||||
and DCE 1.1: Authentication and Security Services.
|
||||
|
||||
This package is based on the github.com/pborman/uuid package (previously named
|
||||
code.google.com/p/go-uuid). It differs from these earlier packages in that
|
||||
a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||
|
||||
###### Install
|
||||
```sh
|
||||
go get github.com/google/uuid
|
||||
```
|
||||
|
||||
###### Documentation
|
||||
[](https://pkg.go.dev/github.com/google/uuid)
|
||||
|
||||
Full `go doc` style documentation for the package can be viewed online without
|
||||
installing this package by using the GoDoc site here:
|
||||
http://pkg.go.dev/github.com/google/uuid
|
||||
80
ca-server/vendor/github.com/google/uuid/dce.go
generated
vendored
80
ca-server/vendor/github.com/google/uuid/dce.go
generated
vendored
@@ -1,80 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A Domain represents a Version 2 domain
|
||||
type Domain byte
|
||||
|
||||
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||
const (
|
||||
Person = Domain(0)
|
||||
Group = Domain(1)
|
||||
Org = Domain(2)
|
||||
)
|
||||
|
||||
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||
//
|
||||
// The domain should be one of Person, Group or Org.
|
||||
// On a POSIX system the id should be the users UID for the Person
|
||||
// domain and the users GID for the Group. The meaning of id for
|
||||
// the domain Org or on non-POSIX systems is site defined.
|
||||
//
|
||||
// For a given domain/id pair the same token may be returned for up to
|
||||
// 7 minutes and 10 seconds.
|
||||
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err == nil {
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||
uuid[9] = byte(domain)
|
||||
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||
}
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() (UUID, error) {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() (UUID, error) {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
// Domain returns the domain for a Version 2 UUID. Domains are only defined
|
||||
// for Version 2 UUIDs.
|
||||
func (uuid UUID) Domain() Domain {
|
||||
return Domain(uuid[9])
|
||||
}
|
||||
|
||||
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
|
||||
// UUIDs.
|
||||
func (uuid UUID) ID() uint32 {
|
||||
return binary.BigEndian.Uint32(uuid[0:4])
|
||||
}
|
||||
|
||||
func (d Domain) String() string {
|
||||
switch d {
|
||||
case Person:
|
||||
return "Person"
|
||||
case Group:
|
||||
return "Group"
|
||||
case Org:
|
||||
return "Org"
|
||||
}
|
||||
return fmt.Sprintf("Domain%d", int(d))
|
||||
}
|
||||
12
ca-server/vendor/github.com/google/uuid/doc.go
generated
vendored
12
ca-server/vendor/github.com/google/uuid/doc.go
generated
vendored
@@ -1,12 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package uuid generates and inspects UUIDs.
|
||||
//
|
||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||
// Services.
|
||||
//
|
||||
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
|
||||
// maps or compared directly.
|
||||
package uuid
|
||||
59
ca-server/vendor/github.com/google/uuid/hash.go
generated
vendored
59
ca-server/vendor/github.com/google/uuid/hash.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Well known namespace IDs and UUIDs
|
||||
var (
|
||||
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||
Nil UUID // empty UUID, all zeros
|
||||
|
||||
// The Max UUID is special form of UUID that is specified to have all 128 bits set to 1.
|
||||
Max = UUID{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
}
|
||||
)
|
||||
|
||||
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||
// data generated by h. The hash should be at least 16 byte in length. The
|
||||
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||
// NewMD5 and NewSHA1.
|
||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
h.Reset()
|
||||
h.Write(space[:]) //nolint:errcheck
|
||||
h.Write(data) //nolint:errcheck
|
||||
s := h.Sum(nil)
|
||||
var uuid UUID
|
||||
copy(uuid[:], s)
|
||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
||||
38
ca-server/vendor/github.com/google/uuid/marshal.go
generated
vendored
38
ca-server/vendor/github.com/google/uuid/marshal.go
generated
vendored
@@ -1,38 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (uuid UUID) MarshalText() ([]byte, error) {
|
||||
var js [36]byte
|
||||
encodeHex(js[:], uuid)
|
||||
return js[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||
id, err := ParseBytes(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*uuid = id
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (uuid UUID) MarshalBinary() ([]byte, error) {
|
||||
return uuid[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
copy(uuid[:], data)
|
||||
return nil
|
||||
}
|
||||
90
ca-server/vendor/github.com/google/uuid/node.go
generated
vendored
90
ca-server/vendor/github.com/google/uuid/node.go
generated
vendored
@@ -1,90 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
nodeMu sync.Mutex
|
||||
ifname string // name of interface being used
|
||||
nodeID [6]byte // hardware for version 1 UUIDs
|
||||
zeroID [6]byte // nodeID with only 0's
|
||||
)
|
||||
|
||||
// NodeInterface returns the name of the interface from which the NodeID was
|
||||
// derived. The interface "user" is returned if the NodeID was set by
|
||||
// SetNodeID.
|
||||
func NodeInterface() string {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return ifname
|
||||
}
|
||||
|
||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||
// If name is "" then the first usable interface found will be used or a random
|
||||
// Node ID will be generated. If a named interface cannot be found then false
|
||||
// is returned.
|
||||
//
|
||||
// SetNodeInterface never fails when name is "".
|
||||
func SetNodeInterface(name string) bool {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return setNodeInterface(name)
|
||||
}
|
||||
|
||||
func setNodeInterface(name string) bool {
|
||||
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||
if iname != "" && addr != nil {
|
||||
ifname = iname
|
||||
copy(nodeID[:], addr)
|
||||
return true
|
||||
}
|
||||
|
||||
// We found no interfaces with a valid hardware address. If name
|
||||
// does not specify a specific interface generate a random Node ID
|
||||
// (section 4.1.6)
|
||||
if name == "" {
|
||||
ifname = "random"
|
||||
randomBits(nodeID[:])
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||
// if not already set.
|
||||
func NodeID() []byte {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
nid := nodeID
|
||||
return nid[:]
|
||||
}
|
||||
|
||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||
// Node ID is not set.
|
||||
func SetNodeID(id []byte) bool {
|
||||
if len(id) < 6 {
|
||||
return false
|
||||
}
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
copy(nodeID[:], id)
|
||||
ifname = "user"
|
||||
return true
|
||||
}
|
||||
|
||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) NodeID() []byte {
|
||||
var node [6]byte
|
||||
copy(node[:], uuid[10:])
|
||||
return node[:]
|
||||
}
|
||||
12
ca-server/vendor/github.com/google/uuid/node_js.go
generated
vendored
12
ca-server/vendor/github.com/google/uuid/node_js.go
generated
vendored
@@ -1,12 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build js
|
||||
|
||||
package uuid
|
||||
|
||||
// getHardwareInterface returns nil values for the JS version of the code.
|
||||
// This removes the "net" dependency, because it is not used in the browser.
|
||||
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
||||
33
ca-server/vendor/github.com/google/uuid/node_net.go
generated
vendored
33
ca-server/vendor/github.com/google/uuid/node_net.go
generated
vendored
@@ -1,33 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !js
|
||||
|
||||
package uuid
|
||||
|
||||
import "net"
|
||||
|
||||
var interfaces []net.Interface // cached list of interfaces
|
||||
|
||||
// getHardwareInterface returns the name and hardware address of interface name.
|
||||
// If name is "" then the name and hardware address of one of the system's
|
||||
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||
// there are no interfaces) then "", nil is returned.
|
||||
//
|
||||
// Only addresses of at least 6 bytes are returned.
|
||||
func getHardwareInterface(name string) (string, []byte) {
|
||||
if interfaces == nil {
|
||||
var err error
|
||||
interfaces, err = net.Interfaces()
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
for _, ifs := range interfaces {
|
||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||
return ifs.Name, ifs.HardwareAddr
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
118
ca-server/vendor/github.com/google/uuid/null.go
generated
vendored
118
ca-server/vendor/github.com/google/uuid/null.go
generated
vendored
@@ -1,118 +0,0 @@
|
||||
// Copyright 2021 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var jsonNull = []byte("null")
|
||||
|
||||
// NullUUID represents a UUID that may be null.
|
||||
// NullUUID implements the SQL driver.Scanner interface so
|
||||
// it can be used as a scan destination:
|
||||
//
|
||||
// var u uuid.NullUUID
|
||||
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
|
||||
// ...
|
||||
// if u.Valid {
|
||||
// // use u.UUID
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
//
|
||||
type NullUUID struct {
|
||||
UUID UUID
|
||||
Valid bool // Valid is true if UUID is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the SQL driver.Scanner interface.
|
||||
func (nu *NullUUID) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
nu.UUID, nu.Valid = Nil, false
|
||||
return nil
|
||||
}
|
||||
|
||||
err := nu.UUID.Scan(value)
|
||||
if err != nil {
|
||||
nu.Valid = false
|
||||
return err
|
||||
}
|
||||
|
||||
nu.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (nu NullUUID) Value() (driver.Value, error) {
|
||||
if !nu.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
// Delegate to UUID Value function
|
||||
return nu.UUID.Value()
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (nu NullUUID) MarshalBinary() ([]byte, error) {
|
||||
if nu.Valid {
|
||||
return nu.UUID[:], nil
|
||||
}
|
||||
|
||||
return []byte(nil), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (nu *NullUUID) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
copy(nu.UUID[:], data)
|
||||
nu.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (nu NullUUID) MarshalText() ([]byte, error) {
|
||||
if nu.Valid {
|
||||
return nu.UUID.MarshalText()
|
||||
}
|
||||
|
||||
return jsonNull, nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (nu *NullUUID) UnmarshalText(data []byte) error {
|
||||
id, err := ParseBytes(data)
|
||||
if err != nil {
|
||||
nu.Valid = false
|
||||
return err
|
||||
}
|
||||
nu.UUID = id
|
||||
nu.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (nu NullUUID) MarshalJSON() ([]byte, error) {
|
||||
if nu.Valid {
|
||||
return json.Marshal(nu.UUID)
|
||||
}
|
||||
|
||||
return jsonNull, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (nu *NullUUID) UnmarshalJSON(data []byte) error {
|
||||
if bytes.Equal(data, jsonNull) {
|
||||
*nu = NullUUID{}
|
||||
return nil // valid null UUID
|
||||
}
|
||||
err := json.Unmarshal(data, &nu.UUID)
|
||||
nu.Valid = err == nil
|
||||
return err
|
||||
}
|
||||
59
ca-server/vendor/github.com/google/uuid/sql.go
generated
vendored
59
ca-server/vendor/github.com/google/uuid/sql.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Scan implements sql.Scanner so UUIDs can be read from databases transparently.
|
||||
// Currently, database types that map to string and []byte are supported. Please
|
||||
// consult database-specific driver documentation for matching types.
|
||||
func (uuid *UUID) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
|
||||
case string:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// see Parse for required string format
|
||||
u, err := Parse(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Scan: %v", err)
|
||||
}
|
||||
|
||||
*uuid = u
|
||||
|
||||
case []byte:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// assumes a simple slice of bytes if 16 bytes
|
||||
// otherwise attempts to parse
|
||||
if len(src) != 16 {
|
||||
return uuid.Scan(string(src))
|
||||
}
|
||||
copy((*uuid)[:], src)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||
// transparently. Currently, UUIDs map to strings. Please consult
|
||||
// database-specific driver documentation for matching types.
|
||||
func (uuid UUID) Value() (driver.Value, error) {
|
||||
return uuid.String(), nil
|
||||
}
|
||||
134
ca-server/vendor/github.com/google/uuid/time.go
generated
vendored
134
ca-server/vendor/github.com/google/uuid/time.go
generated
vendored
@@ -1,134 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||
// 1582.
|
||||
type Time int64
|
||||
|
||||
const (
|
||||
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||
unix = 2440587 // Julian day of 1 Jan 1970
|
||||
epoch = unix - lillian // Days between epochs
|
||||
g1582 = epoch * 86400 // seconds between epochs
|
||||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||
)
|
||||
|
||||
var (
|
||||
timeMu sync.Mutex
|
||||
lasttime uint64 // last time we returned
|
||||
clockSeq uint16 // clock sequence for this run
|
||||
|
||||
timeNow = time.Now // for testing
|
||||
)
|
||||
|
||||
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||
// epoch of 1 Jan 1970.
|
||||
func (t Time) UnixTime() (sec, nsec int64) {
|
||||
sec = int64(t - g1582ns100)
|
||||
nsec = (sec % 10000000) * 100
|
||||
sec /= 10000000
|
||||
return sec, nsec
|
||||
}
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||
// is returned if the current time cannot be determined.
|
||||
func GetTime() (Time, uint16, error) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return getTime()
|
||||
}
|
||||
|
||||
func getTime() (Time, uint16, error) {
|
||||
t := timeNow()
|
||||
|
||||
// If we don't have a clock sequence already, set one.
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||
|
||||
// If time has gone backwards with this clock sequence then we
|
||||
// increment the clock sequence
|
||||
if now <= lasttime {
|
||||
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
|
||||
}
|
||||
lasttime = now
|
||||
return Time(now), clockSeq, nil
|
||||
}
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
||||
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||
//
|
||||
// The uuid package does not use global static storage for the clock sequence or
|
||||
// the last time a UUID was generated. Unless SetClockSequence is used, a new
|
||||
// random clock sequence is generated the first time a clock sequence is
|
||||
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
|
||||
func ClockSequence() int {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return clockSequence()
|
||||
}
|
||||
|
||||
func clockSequence() int {
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
return int(clockSeq & 0x3fff)
|
||||
}
|
||||
|
||||
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||
// -1 causes a new sequence to be generated.
|
||||
func SetClockSequence(seq int) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
setClockSequence(seq)
|
||||
}
|
||||
|
||||
func setClockSequence(seq int) {
|
||||
if seq == -1 {
|
||||
var b [2]byte
|
||||
randomBits(b[:]) // clock sequence
|
||||
seq = int(b[0])<<8 | int(b[1])
|
||||
}
|
||||
oldSeq := clockSeq
|
||||
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||
if oldSeq != clockSeq {
|
||||
lasttime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||
// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs.
|
||||
func (uuid UUID) Time() Time {
|
||||
var t Time
|
||||
switch uuid.Version() {
|
||||
case 6:
|
||||
time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110
|
||||
t = Time(time)
|
||||
case 7:
|
||||
time := binary.BigEndian.Uint64(uuid[:8])
|
||||
t = Time((time>>16)*10000 + g1582ns100)
|
||||
default: // forward compatible
|
||||
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||
t = Time(time)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// ClockSequence returns the clock sequence encoded in uuid.
|
||||
// The clock sequence is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) ClockSequence() int {
|
||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
|
||||
}
|
||||
43
ca-server/vendor/github.com/google/uuid/util.go
generated
vendored
43
ca-server/vendor/github.com/google/uuid/util.go
generated
vendored
@@ -1,43 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// randomBits completely fills slice b with random data.
|
||||
func randomBits(b []byte) {
|
||||
if _, err := io.ReadFull(rander, b); err != nil {
|
||||
panic(err.Error()) // rand should never fail
|
||||
}
|
||||
}
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts hex characters x1 and x2 into a byte.
|
||||
func xtob(x1, x2 byte) (byte, bool) {
|
||||
b1 := xvalues[x1]
|
||||
b2 := xvalues[x2]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
||||
365
ca-server/vendor/github.com/google/uuid/uuid.go
generated
vendored
365
ca-server/vendor/github.com/google/uuid/uuid.go
generated
vendored
@@ -1,365 +0,0 @@
|
||||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
// 4122.
|
||||
type UUID [16]byte
|
||||
|
||||
// A Version represents a UUID's version.
|
||||
type Version byte
|
||||
|
||||
// A Variant represents a UUID's variant.
|
||||
type Variant byte
|
||||
|
||||
// Constants returned by Variant.
|
||||
const (
|
||||
Invalid = Variant(iota) // Invalid UUID
|
||||
RFC4122 // The variant specified in RFC4122
|
||||
Reserved // Reserved, NCS backward compatibility.
|
||||
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||
Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
const randPoolSize = 16 * 16
|
||||
|
||||
var (
|
||||
rander = rand.Reader // random function
|
||||
poolEnabled = false
|
||||
poolMu sync.Mutex
|
||||
poolPos = randPoolSize // protected with poolMu
|
||||
pool [randPoolSize]byte // protected with poolMu
|
||||
)
|
||||
|
||||
type invalidLengthError struct{ len int }
|
||||
|
||||
func (err invalidLengthError) Error() string {
|
||||
return fmt.Sprintf("invalid UUID length: %d", err.len)
|
||||
}
|
||||
|
||||
// IsInvalidLengthError is matcher function for custom error invalidLengthError
|
||||
func IsInvalidLengthError(err error) bool {
|
||||
_, ok := err.(invalidLengthError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both
|
||||
// the standard UUID forms defined in RFC 4122
|
||||
// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition,
|
||||
// Parse accepts non-standard strings such as the raw hex encoding
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings,
|
||||
// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are
|
||||
// examined in the latter case. Parse should not be used to validate strings as
|
||||
// it parses non-standard encodings as indicated above.
|
||||
func Parse(s string) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(s) {
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36:
|
||||
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9:
|
||||
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
case 36 + 2:
|
||||
s = s[1:]
|
||||
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
case 32:
|
||||
var ok bool
|
||||
for i := range uuid {
|
||||
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, invalidLengthError{len(s)}
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34,
|
||||
} {
|
||||
v, ok := xtob(s[x], s[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||
func ParseBytes(b []byte) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(b) {
|
||||
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||
}
|
||||
b = b[9:]
|
||||
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
b = b[1:]
|
||||
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
var ok bool
|
||||
for i := 0; i < 32; i += 2 {
|
||||
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, invalidLengthError{len(b)}
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34,
|
||||
} {
|
||||
v, ok := xtob(b[x], b[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||
func MustParse(s string) UUID {
|
||||
uuid, err := Parse(s)
|
||||
if err != nil {
|
||||
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||
// does not have a length of 16. The bytes are copied from the slice.
|
||||
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||
err = uuid.UnmarshalBinary(b)
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// Must returns uuid if err is nil and panics otherwise.
|
||||
func Must(uuid UUID, err error) UUID {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
// It returns an error if the format is invalid, otherwise nil.
|
||||
func Validate(s string) error {
|
||||
switch len(s) {
|
||||
// Standard UUID format
|
||||
case 36:
|
||||
|
||||
// UUID with "urn:uuid:" prefix
|
||||
case 36 + 9:
|
||||
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||
return fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
// UUID enclosed in braces
|
||||
case 36 + 2:
|
||||
if s[0] != '{' || s[len(s)-1] != '}' {
|
||||
return fmt.Errorf("invalid bracketed UUID format")
|
||||
}
|
||||
s = s[1 : len(s)-1]
|
||||
|
||||
// UUID without hyphens
|
||||
case 32:
|
||||
for i := 0; i < len(s); i += 2 {
|
||||
_, ok := xtob(s[i], s[i+1])
|
||||
if !ok {
|
||||
return errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return invalidLengthError{len(s)}
|
||||
}
|
||||
|
||||
// Check for standard UUID format
|
||||
if len(s) == 36 {
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return errors.New("invalid UUID format")
|
||||
}
|
||||
for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
|
||||
if _, ok := xtob(s[x], s[x+1]); !ok {
|
||||
return errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// , or "" if uuid is invalid.
|
||||
func (uuid UUID) String() string {
|
||||
var buf [36]byte
|
||||
encodeHex(buf[:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// URN returns the RFC 2141 URN form of uuid,
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||
func (uuid UUID) URN() string {
|
||||
var buf [36 + 9]byte
|
||||
copy(buf[:], "urn:uuid:")
|
||||
encodeHex(buf[9:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
func encodeHex(dst []byte, uuid UUID) {
|
||||
hex.Encode(dst, uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
hex.Encode(dst[14:18], uuid[6:8])
|
||||
dst[18] = '-'
|
||||
hex.Encode(dst[19:23], uuid[8:10])
|
||||
dst[23] = '-'
|
||||
hex.Encode(dst[24:], uuid[10:])
|
||||
}
|
||||
|
||||
// Variant returns the variant encoded in uuid.
|
||||
func (uuid UUID) Variant() Variant {
|
||||
switch {
|
||||
case (uuid[8] & 0xc0) == 0x80:
|
||||
return RFC4122
|
||||
case (uuid[8] & 0xe0) == 0xc0:
|
||||
return Microsoft
|
||||
case (uuid[8] & 0xe0) == 0xe0:
|
||||
return Future
|
||||
default:
|
||||
return Reserved
|
||||
}
|
||||
}
|
||||
|
||||
// Version returns the version of uuid.
|
||||
func (uuid UUID) Version() Version {
|
||||
return Version(uuid[6] >> 4)
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v > 15 {
|
||||
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||
}
|
||||
return fmt.Sprintf("VERSION_%d", v)
|
||||
}
|
||||
|
||||
func (v Variant) String() string {
|
||||
switch v {
|
||||
case RFC4122:
|
||||
return "RFC4122"
|
||||
case Reserved:
|
||||
return "Reserved"
|
||||
case Microsoft:
|
||||
return "Microsoft"
|
||||
case Future:
|
||||
return "Future"
|
||||
case Invalid:
|
||||
return "Invalid"
|
||||
}
|
||||
return fmt.Sprintf("BadVariant%d", int(v))
|
||||
}
|
||||
|
||||
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||
// If r.Read returns an error when the package requests random data then
|
||||
// a panic will be issued.
|
||||
//
|
||||
// Calling SetRand with nil sets the random number generator to the default
|
||||
// generator.
|
||||
func SetRand(r io.Reader) {
|
||||
if r == nil {
|
||||
rander = rand.Reader
|
||||
return
|
||||
}
|
||||
rander = r
|
||||
}
|
||||
|
||||
// EnableRandPool enables internal randomness pool used for Random
|
||||
// (Version 4) UUID generation. The pool contains random bytes read from
|
||||
// the random number generator on demand in batches. Enabling the pool
|
||||
// may improve the UUID generation throughput significantly.
|
||||
//
|
||||
// Since the pool is stored on the Go heap, this feature may be a bad fit
|
||||
// for security sensitive applications.
|
||||
//
|
||||
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||
// only be called when there is no possibility that New or any other
|
||||
// UUID Version 4 generation function will be called concurrently.
|
||||
func EnableRandPool() {
|
||||
poolEnabled = true
|
||||
}
|
||||
|
||||
// DisableRandPool disables the randomness pool if it was previously
|
||||
// enabled with EnableRandPool.
|
||||
//
|
||||
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||
// only be called when there is no possibility that New or any other
|
||||
// UUID Version 4 generation function will be called concurrently.
|
||||
func DisableRandPool() {
|
||||
poolEnabled = false
|
||||
defer poolMu.Unlock()
|
||||
poolMu.Lock()
|
||||
poolPos = randPoolSize
|
||||
}
|
||||
|
||||
// UUIDs is a slice of UUID types.
|
||||
type UUIDs []UUID
|
||||
|
||||
// Strings returns a string slice containing the string form of each UUID in uuids.
|
||||
func (uuids UUIDs) Strings() []string {
|
||||
var uuidStrs = make([]string, len(uuids))
|
||||
for i, uuid := range uuids {
|
||||
uuidStrs[i] = uuid.String()
|
||||
}
|
||||
return uuidStrs
|
||||
}
|
||||
44
ca-server/vendor/github.com/google/uuid/version1.go
generated
vendored
44
ca-server/vendor/github.com/google/uuid/version1.go
generated
vendored
@@ -1,44 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewUUID returns nil and an error.
|
||||
//
|
||||
// In most cases, New should be used.
|
||||
func NewUUID() (UUID, error) {
|
||||
var uuid UUID
|
||||
now, seq, err := GetTime()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
timeLow := uint32(now & 0xffffffff)
|
||||
timeMid := uint16((now >> 32) & 0xffff)
|
||||
timeHi := uint16((now >> 48) & 0x0fff)
|
||||
timeHi |= 0x1000 // Version 1
|
||||
|
||||
binary.BigEndian.PutUint32(uuid[0:], timeLow)
|
||||
binary.BigEndian.PutUint16(uuid[4:], timeMid)
|
||||
binary.BigEndian.PutUint16(uuid[6:], timeHi)
|
||||
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
copy(uuid[10:], nodeID[:])
|
||||
nodeMu.Unlock()
|
||||
|
||||
return uuid, nil
|
||||
}
|
||||
76
ca-server/vendor/github.com/google/uuid/version4.go
generated
vendored
76
ca-server/vendor/github.com/google/uuid/version4.go
generated
vendored
@@ -1,76 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "io"
|
||||
|
||||
// New creates a new random UUID or panics. New is equivalent to
|
||||
// the expression
|
||||
//
|
||||
// uuid.Must(uuid.NewRandom())
|
||||
func New() UUID {
|
||||
return Must(NewRandom())
|
||||
}
|
||||
|
||||
// NewString creates a new random UUID and returns it as a string or panics.
|
||||
// NewString is equivalent to the expression
|
||||
//
|
||||
// uuid.New().String()
|
||||
func NewString() string {
|
||||
return Must(NewRandom()).String()
|
||||
}
|
||||
|
||||
// NewRandom returns a Random (Version 4) UUID.
|
||||
//
|
||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||
//
|
||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() (UUID, error) {
|
||||
if !poolEnabled {
|
||||
return NewRandomFromReader(rander)
|
||||
}
|
||||
return newRandomFromPool()
|
||||
}
|
||||
|
||||
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
|
||||
func NewRandomFromReader(r io.Reader) (UUID, error) {
|
||||
var uuid UUID
|
||||
_, err := io.ReadFull(r, uuid[:])
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
func newRandomFromPool() (UUID, error) {
|
||||
var uuid UUID
|
||||
poolMu.Lock()
|
||||
if poolPos == randPoolSize {
|
||||
_, err := io.ReadFull(rander, pool[:])
|
||||
if err != nil {
|
||||
poolMu.Unlock()
|
||||
return Nil, err
|
||||
}
|
||||
poolPos = 0
|
||||
}
|
||||
copy(uuid[:], pool[poolPos:(poolPos+16)])
|
||||
poolPos += 16
|
||||
poolMu.Unlock()
|
||||
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
||||
56
ca-server/vendor/github.com/google/uuid/version6.go
generated
vendored
56
ca-server/vendor/github.com/google/uuid/version6.go
generated
vendored
@@ -1,56 +0,0 @@
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality.
|
||||
// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs.
|
||||
// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.
|
||||
//
|
||||
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6
|
||||
//
|
||||
// NewV6 returns a Version 6 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewV6 returns Nil and an error.
|
||||
func NewV6() (UUID, error) {
|
||||
var uuid UUID
|
||||
now, seq, err := GetTime()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
/*
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| time_high |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| time_mid | time_low_and_version |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|clk_seq_hi_res | clk_seq_low | node (0-1) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| node (2-5) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
binary.BigEndian.PutUint64(uuid[0:], uint64(now))
|
||||
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||
|
||||
uuid[6] = 0x60 | (uuid[6] & 0x0F)
|
||||
uuid[8] = 0x80 | (uuid[8] & 0x3F)
|
||||
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
copy(uuid[10:], nodeID[:])
|
||||
nodeMu.Unlock()
|
||||
|
||||
return uuid, nil
|
||||
}
|
||||
104
ca-server/vendor/github.com/google/uuid/version7.go
generated
vendored
104
ca-server/vendor/github.com/google/uuid/version7.go
generated
vendored
@@ -1,104 +0,0 @@
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// UUID version 7 features a time-ordered value field derived from the widely
|
||||
// implemented and well known Unix Epoch timestamp source,
|
||||
// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded.
|
||||
// As well as improved entropy characteristics over versions 1 or 6.
|
||||
//
|
||||
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7
|
||||
//
|
||||
// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.
|
||||
//
|
||||
// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||
// On error, NewV7 returns Nil and an error
|
||||
func NewV7() (UUID, error) {
|
||||
uuid, err := NewRandom()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
makeV7(uuid[:])
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||
// it use NewRandomFromReader fill random bits.
|
||||
// On error, NewV7FromReader returns Nil and an error.
|
||||
func NewV7FromReader(r io.Reader) (UUID, error) {
|
||||
uuid, err := NewRandomFromReader(r)
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
makeV7(uuid[:])
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6])
|
||||
// uuid[8] already has the right version number (Variant is 10)
|
||||
// see function NewV7 and NewV7FromReader
|
||||
func makeV7(uuid []byte) {
|
||||
/*
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| unix_ts_ms |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| unix_ts_ms | ver | rand_a (12 bit seq) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|var| rand_b |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| rand_b |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
_ = uuid[15] // bounds check
|
||||
|
||||
t, s := getV7Time()
|
||||
|
||||
uuid[0] = byte(t >> 40)
|
||||
uuid[1] = byte(t >> 32)
|
||||
uuid[2] = byte(t >> 24)
|
||||
uuid[3] = byte(t >> 16)
|
||||
uuid[4] = byte(t >> 8)
|
||||
uuid[5] = byte(t)
|
||||
|
||||
uuid[6] = 0x70 | (0x0F & byte(s>>8))
|
||||
uuid[7] = byte(s)
|
||||
}
|
||||
|
||||
// lastV7time is the last time we returned stored as:
|
||||
//
|
||||
// 52 bits of time in milliseconds since epoch
|
||||
// 12 bits of (fractional nanoseconds) >> 8
|
||||
var lastV7time int64
|
||||
|
||||
const nanoPerMilli = 1000000
|
||||
|
||||
// getV7Time returns the time in milliseconds and nanoseconds / 256.
|
||||
// The returned (milli << 12 + seq) is guarenteed to be greater than
|
||||
// (milli << 12 + seq) returned by any previous call to getV7Time.
|
||||
func getV7Time() (milli, seq int64) {
|
||||
timeMu.Lock()
|
||||
defer timeMu.Unlock()
|
||||
|
||||
nano := timeNow().UnixNano()
|
||||
milli = nano / nanoPerMilli
|
||||
// Sequence number is between 0 and 3906 (nanoPerMilli>>8)
|
||||
seq = (nano - milli*nanoPerMilli) >> 8
|
||||
now := milli<<12 + seq
|
||||
if now <= lastV7time {
|
||||
now = lastV7time + 1
|
||||
milli = now >> 12
|
||||
seq = now & 0xfff
|
||||
}
|
||||
lastV7time = now
|
||||
return milli, seq
|
||||
}
|
||||
3
ca-server/vendor/modules.txt
vendored
3
ca-server/vendor/modules.txt
vendored
@@ -16,9 +16,6 @@ github.com/go-sql-driver/mysql
|
||||
## explicit; go 1.18
|
||||
github.com/go-viper/mapstructure/v2
|
||||
github.com/go-viper/mapstructure/v2/internal/errors
|
||||
# github.com/google/uuid v1.6.0
|
||||
## explicit
|
||||
github.com/google/uuid
|
||||
# github.com/gorilla/mux v1.8.1
|
||||
## explicit; go 1.20
|
||||
github.com/gorilla/mux
|
||||
|
||||
Reference in New Issue
Block a user