You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2020/06/06 01:35:37 UTC
[incubator-apisix-dashboard] 01/01: feat: refactor SSL
This is an automated email from the ASF dual-hosted git repository.
juzhiyuan pushed a commit to branch feat-ssl
in repository https://gitbox.apache.org/repos/asf/incubator-apisix-dashboard.git
commit 8b7a68b5290900e8a39a07ddf204b4e51149438c
Author: juzhiyuan <jj...@gmail.com>
AuthorDate: Sat Jun 6 09:35:13 2020 +0800
feat: refactor SSL
---
package.json | 1 -
src/pages/ssl/Create.tsx | 5 +-
.../ssl/components/CertificateUploader/index.tsx | 54 +++++----------
src/pages/ssl/components/Step2/index.tsx | 81 +++++++++++-----------
src/pages/ssl/service.ts | 28 +++++++-
yarn.lock | 5 --
6 files changed, 85 insertions(+), 89 deletions(-)
diff --git a/package.json b/package.json
index 1e38476..947a740 100644
--- a/package.json
+++ b/package.json
@@ -53,7 +53,6 @@
"classnames": "^2.2.6",
"lodash": "^4.17.15",
"moment": "^2.25.3",
- "node-forge": "^0.9.1",
"nzh": "^1.0.3",
"omit.js": "^1.0.2",
"path-to-regexp": "2.4.0",
diff --git a/src/pages/ssl/Create.tsx b/src/pages/ssl/Create.tsx
index 0ec6ff4..836a00a 100644
--- a/src/pages/ssl/Create.tsx
+++ b/src/pages/ssl/Create.tsx
@@ -1,7 +1,6 @@
import React, { useState } from 'react';
import { Card, Steps } from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
-import { UploadFile } from 'antd/es/upload/interface';
import Step1 from './components/Step1';
import Step2 from './components/Step2';
import Step3 from './components/Step3';
@@ -15,9 +14,7 @@ export interface FormData {
sni?: string;
cert?: string;
key?: string;
- expireTime?: Date;
- publicKeyFileList?: UploadFile[];
- privateKeyFileList?: UploadFile[];
+ expireTime?: Date | string;
}
export interface StepProps {
diff --git a/src/pages/ssl/components/CertificateUploader/index.tsx b/src/pages/ssl/components/CertificateUploader/index.tsx
index aaa35d6..135240d 100644
--- a/src/pages/ssl/components/CertificateUploader/index.tsx
+++ b/src/pages/ssl/components/CertificateUploader/index.tsx
@@ -1,36 +1,31 @@
import React from 'react';
-import { Form, Button, Upload, message } from 'antd';
+import { Form, Button, Upload } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { UploadFile } from 'antd/lib/upload/interface';
import { useForm } from 'antd/es/form/util';
-import forge from 'node-forge';
-import { FormData } from '../../Create';
import styles from '../../Create.less';
-export interface AltName {
- value: string;
-}
-
export type UploadType = 'PUBLIC_KEY' | 'PRIVATE_KEY';
export interface UploadPublicSuccessData {
- sni: string;
cert: string;
- expireTime: Date;
- publicKeyFileList: UploadFile[];
+ publicKeyList: UploadFile[];
}
export interface UploadPrivateSuccessData {
key: string;
- privateKeyFileList: UploadFile[];
+ privateKeyList: UploadFile[];
}
interface UploaderProps {
+ data: {
+ publicKeyList: UploadFile[];
+ privateKeyList: UploadFile[];
+ };
onSuccess(data: UploadPublicSuccessData | UploadPrivateSuccessData): void;
onRemove(type: UploadType): void;
- data: FormData;
}
const CertificateUploader: React.FC<UploaderProps> = ({ onSuccess, onRemove, data }) => {
- const { publicKeyFileList = [], privateKeyFileList = [] } = data;
+ const { publicKeyList = [], privateKeyList = [] } = data;
const [form] = useForm();
const genUploadFile = (name = ''): UploadFile => {
@@ -50,26 +45,15 @@ const CertificateUploader: React.FC<UploaderProps> = ({ onSuccess, onRemove, dat
fileReader.onload = function (event) {
const { result } = event.currentTarget as any;
if (type === 'PUBLIC_KEY') {
- try {
- const cert = forge.pki.certificateFromPem(result);
- const altNames = (cert.extensions.find((item) => item.name === 'subjectAltName')
- .altNames as AltName[])
- .map((item) => item.value)
- .join(';');
- const uploadPublicData: UploadPublicSuccessData = {
- sni: altNames,
- cert: result,
- expireTime: cert.validity.notAfter,
- publicKeyFileList: [genUploadFile(fileName)],
- };
- onSuccess(uploadPublicData);
- } catch (error) {
- message.error('证书解析失败');
- }
+ const uploadPublicData: UploadPublicSuccessData = {
+ cert: result,
+ publicKeyList: [genUploadFile(fileName)],
+ };
+ onSuccess(uploadPublicData);
} else {
const uploadprivateData: UploadPrivateSuccessData = {
key: result,
- privateKeyFileList: [genUploadFile(fileName)],
+ privateKeyList: [genUploadFile(fileName)],
};
onSuccess(uploadprivateData);
}
@@ -85,26 +69,24 @@ const CertificateUploader: React.FC<UploaderProps> = ({ onSuccess, onRemove, dat
<Form form={form} layout="horizontal" className={styles.stepForm}>
<Form.Item>
<Upload
- accept=".pem"
className={styles.stepForm}
onRemove={() => onRemove('PUBLIC_KEY')}
- fileList={publicKeyFileList}
+ fileList={publicKeyList}
beforeUpload={(file, fileList) => beforeUpload(file, fileList, 'PUBLIC_KEY')}
>
- <Button disabled={publicKeyFileList.length === 1}>
+ <Button disabled={publicKeyList.length === 1}>
<UploadOutlined /> 点击上传公钥
</Button>
</Upload>
</Form.Item>
<Form.Item>
<Upload
- accept=".key"
className={styles.stepForm}
onRemove={() => onRemove('PRIVATE_KEY')}
- fileList={privateKeyFileList}
+ fileList={privateKeyList}
beforeUpload={(file, fileList) => beforeUpload(file, fileList, 'PRIVATE_KEY')}
>
- <Button disabled={privateKeyFileList.length === 1}>
+ <Button disabled={privateKeyList.length === 1}>
<UploadOutlined /> 点击上传私钥
</Button>
</Upload>
diff --git a/src/pages/ssl/components/Step2/index.tsx b/src/pages/ssl/components/Step2/index.tsx
index 51c320f..d15dc0e 100644
--- a/src/pages/ssl/components/Step2/index.tsx
+++ b/src/pages/ssl/components/Step2/index.tsx
@@ -1,71 +1,70 @@
-import React from 'react';
-import { Form, Button, message } from 'antd';
-import forge from 'node-forge';
+import React, { useState } from 'react';
+import { Form, Button } from 'antd';
+import { UploadFile } from 'antd/lib/upload/interface';
+
import CertificateForm from '../CertificateForm';
-import {
- CertificateUploader,
- UploadPublicSuccessData,
- UploadPrivateSuccessData,
- UploadType,
- AltName,
-} from '../CertificateUploader';
+import { CertificateUploader, UploadType } from '../CertificateUploader';
import { StepProps } from '../../Create';
+import { verifyKeyPaire } from '../../service';
const Step2: React.FC<StepProps> = ({ onStepChange, onFormChange, data }) => {
const [form] = Form.useForm();
const { validateFields } = form;
+ const [publicKeyList, setPublicKeyList] = useState<UploadFile[]>([]);
+ const [privateKeyList, setPrivateKeyList] = useState<UploadFile[]>([]);
+
const onValidateForm = async () => {
- if (data.createType === 'UPLOAD') {
- if (!data.key || !data.cert) {
- message.error('请检查证书');
- return;
- }
- onStepChange(2);
- }
- if (data.createType === 'INPUT') {
- validateFields().then((value) => {
- try {
- const cert = forge.pki.certificateFromPem(value.cert);
- const altNames = (cert.extensions.find((item) => item.name === 'subjectAltName')
- .altNames as AltName[])
- .map((item) => item.value)
- .join(';');
- onFormChange({ ...value, sni: altNames, expireTime: cert.validity.notAfter });
- onStepChange(2);
- } catch (error) {
- message.error('证书解析失败');
- }
+ let keyPaire = { cert: '', key: '' };
+ validateFields()
+ .then((value) => {
+ keyPaire = { cert: value.cert, key: value.key };
+ return verifyKeyPaire(value.cert, value.key);
+ })
+ .then((_data) => {
+ const { snis, validity_end } = _data.data;
+ onFormChange({
+ ...keyPaire,
+ sni: snis.join(';'),
+ expireTime: new Date(validity_end * 1000).toLocaleString(),
+ });
+ onStepChange(2);
});
- }
- };
- const onUploadSuccess = (
- uploadSuccessData: UploadPublicSuccessData | UploadPrivateSuccessData,
- ) => {
- onFormChange(uploadSuccessData);
};
+
const onRemove = (type: UploadType) => {
if (type === 'PUBLIC_KEY') {
onFormChange({
- publicKeyFileList: [],
cert: '',
sni: '',
expireTime: undefined,
});
+ setPublicKeyList([]);
} else {
onFormChange({
- privateKeyFileList: [],
key: '',
});
+ setPrivateKeyList([]);
}
};
return (
<>
- {Boolean(data.createType === 'INPUT') && (
+ <div style={data.createType === 'INPUT' ? {} : { display: 'none' }}>
<CertificateForm mode="EDIT" form={form} data={data} />
- )}
+ </div>
{Boolean(data.createType === 'UPLOAD') && (
- <CertificateUploader onSuccess={onUploadSuccess} onRemove={onRemove} data={data} />
+ <CertificateUploader
+ onSuccess={(_data: any) => {
+ form.setFieldsValue(_data);
+ if (_data.cert) {
+ setPublicKeyList(_data.publicKeyList);
+ } else {
+ setPrivateKeyList(_data.privateKeyList);
+ }
+ }}
+ onRemove={onRemove}
+ data={{ publicKeyList, privateKeyList }}
+ />
)}
<div style={{ width: '100%', textAlign: 'center' }}>
<Button
diff --git a/src/pages/ssl/service.ts b/src/pages/ssl/service.ts
index c699570..d122aa6 100644
--- a/src/pages/ssl/service.ts
+++ b/src/pages/ssl/service.ts
@@ -2,7 +2,7 @@ import { request } from 'umi';
import { transformFetchListData, transformFetchItemData } from '@/transforms/global';
export const fetchList = () =>
- request('/ssl').then((data) => transformFetchListData<SSLModule.SSL>(data));
+ request('/ssls').then((data) => transformFetchListData<SSLModule.SSL>(data));
export const fetchItem = (key: string) =>
request(`/ssl/${key}`).then((data) => transformFetchItemData<SSLModule.SSL>(data));
@@ -13,7 +13,31 @@ export const remove = (key: string) =>
});
export const create = (data: SSLModule.SSL) =>
- request('/ssl', {
+ request('/ssls', {
method: 'POST',
data,
});
+
+type VerifyKeyPaireProps = {
+ code: string;
+ msg: string;
+ data: {
+ id: string;
+ create_time: number;
+ update_time: number;
+ validity_start: number;
+ validity_end: number;
+ snis: string[];
+ status: number;
+ };
+};
+
+/**
+ * 1. 校验证书是否匹配
+ * 2. 解析公钥内容
+ * */
+export const verifyKeyPaire = (cert = '', key = ''): Promise<VerifyKeyPaireProps> =>
+ request('/check_ssl_cert', {
+ method: 'POST',
+ data: { cert, key },
+ });
diff --git a/yarn.lock b/yarn.lock
index af5da19..b1b516e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11998,11 +11998,6 @@ node-fetch@^1.0.1:
encoding "^0.1.11"
is-stream "^1.0.1"
-node-forge@^0.9.1:
- version "0.9.1"
- resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5"
- integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==
-
node-import-ts@^1.0.1, node-import-ts@^1.0.2:
version "1.0.5"
resolved "https://registry.npmjs.org/node-import-ts/-/node-import-ts-1.0.5.tgz#2b5aef3c8fa9babc9d1f948ddfeb62231c18d4f8"