First Commit
@@ -0,0 +1,26 @@
|
||||
# --- Server 系統設定 ---
|
||||
PORT=5060
|
||||
NODE_ENV=development
|
||||
|
||||
# --- MariaDB 資料庫連線設定 ---
|
||||
DB_HOST=localhost
|
||||
DB_PORT=3306
|
||||
DB_USER=root
|
||||
DB_PASSWORD="1qazCDE#"
|
||||
DB_NAME=eis_demo
|
||||
|
||||
# --- Mail 寄送設定 (以 Gmail 為例) ---
|
||||
# 注意:若使用 Gmail,請務必開啟「兩步驟驗證」並申請「應用程式密碼」
|
||||
MAIL_USER=kylinsys@gmail.com
|
||||
MAIL_PASS=owgj hajw iuum txjm
|
||||
|
||||
# --- 檔案上傳設定 ---
|
||||
UPLOAD_PATH=./public/upload
|
||||
# 限制上傳大小 (100MB)
|
||||
MAX_FILE_SIZE=104857600
|
||||
|
||||
# SSL 設定 (只有在 Node.js 直接處理 HTTPS 時需要)
|
||||
ENABLE_HTTPS=true
|
||||
SSL_KEY_PATH=./ssl/private.key
|
||||
SSL_CRT_PATH=./ssl/certificate.crt
|
||||
HTTPS_PORT=8033
|
||||
@@ -0,0 +1,7 @@
|
||||
Rem ************************************************
|
||||
Rem 執行 Node.js 的 mysql Server 端程式
|
||||
Rem ************************************************
|
||||
|
||||
cd C:\api\mariadb-v2
|
||||
node server.js
|
||||
pause
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "mariadb-v2",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node server.js",
|
||||
"dev": "nodemon server.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.3",
|
||||
"express": "^5.2.1",
|
||||
"helmet": "^8.1.0",
|
||||
"morgan": "^1.10.1",
|
||||
"multer": "^2.0.2",
|
||||
"mysql2": "^3.16.0",
|
||||
"node-schedule": "^2.1.1",
|
||||
"nodemailer": "^7.0.12",
|
||||
"winston": "^3.19.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.11"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 314 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 824 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 528 KiB |
|
After Width: | Height: | Size: 471 KiB |
|
After Width: | Height: | Size: 484 KiB |
|
After Width: | Height: | Size: 574 KiB |
|
After Width: | Height: | Size: 535 KiB |
|
After Width: | Height: | Size: 769 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
@@ -0,0 +1,41 @@
|
||||
/my-api-v2
|
||||
├── .env # 環境變數 (DB 帳密, Mail 帳密)
|
||||
├── server.js # 主程式 (Entry Point)
|
||||
├── src/
|
||||
│ ├── config/
|
||||
│ │ └── db.js # MariaDB 連線池設定
|
||||
│ ├── services/
|
||||
│ │ ├── ormService.js # 核心 ORM 與 SP 邏輯
|
||||
│ │ ├── uploadService.js # 檔案上傳邏輯
|
||||
│ │ └── mailService.js # 郵件與排程邏輯
|
||||
│ └── utils/
|
||||
│ └── helper.js # 通用工具函式 (quotstr, date format)
|
||||
└── public/upload # 檔案上傳目錄
|
||||
|
||||
>> https://gemini.google.com/app/57091040afbd48e1
|
||||
|
||||
|
||||
# 1. 初始化 npm 專案 (若尚未執行)
|
||||
npm init -y
|
||||
|
||||
# 2. 安裝核心 Web 框架與安全套件
|
||||
npm install express cors helmet dotenv
|
||||
|
||||
# 3. 安裝資料庫驅動 (MariaDB/MySQL)
|
||||
npm install mysql2
|
||||
|
||||
# 4. 安裝檔案處理與上傳套件
|
||||
npm install multer
|
||||
|
||||
# 5. 安裝郵件與排程套件
|
||||
npm install nodemailer node-schedule
|
||||
|
||||
# 6. 安裝進階 Log 管理系統
|
||||
npm install morgan winston winston-daily-rotate-file
|
||||
|
||||
# 7. (選用) 安裝開發環境自動重啟工具
|
||||
npm install --save-dev nodemon
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const helmet = require('helmet');
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
const morgan = require('morgan');
|
||||
const logger = require('./src/utils/logger');
|
||||
|
||||
require('dotenv').config();
|
||||
|
||||
const ormService = require('./src/services/ormService');
|
||||
const mailService = require('./src/services/mailService');
|
||||
const upload = require('./src/services/uploadService');
|
||||
|
||||
const app = express();
|
||||
|
||||
// 整合 Morgan 到 Winston
|
||||
app.use(morgan('combined', {
|
||||
stream: { write: message => logger.info(message.trim()) }
|
||||
}));
|
||||
|
||||
// --- Middleware ---
|
||||
const corsOptions = {
|
||||
origin: [
|
||||
'https://app.gex.com.tw', // 您的正式環境前端
|
||||
'http://localhost:3000' // 本地開發測試用
|
||||
],
|
||||
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
allowedHeaders: ['Content-Type', 'Authorization', 'token'], // 確保 token 能被傳送
|
||||
credentials: true, // 如果需要帶 Cookie
|
||||
optionsSuccessStatus: 200
|
||||
};
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
|
||||
app.use(helmet());
|
||||
app.use(express.json({ limit: '100mb' }));
|
||||
app.use(express.urlencoded({ extended: true, limit: '100mb' }));
|
||||
//app.use('/static', express.static('public'));
|
||||
app.use(express.static(__dirname + '/public')); //Serves resources from public folder
|
||||
|
||||
// 啟動郵件排程
|
||||
mailService.initAutoMail().then(() => console.log('?? Mail Scheduler Started.'));
|
||||
|
||||
// --- Routes (保持不變) ---
|
||||
// 支援 v1 (舊版) 與 v3 (新版)
|
||||
const ormRoutes = ['/xapi/v1/:dbname/:name/:dsNo', '/xapi/v2/:dbname/:name/:dsNo', '/xapi/v3/:dbname/:name/:dsNo'];
|
||||
|
||||
app.post(ormRoutes, async (req, res, next) => {
|
||||
try {
|
||||
const params = ormService.prepareOrmPayload(req);
|
||||
// 增加一個 log 觀察是哪個路徑進來的
|
||||
logger.info(`Incoming Request: ${req.url} -> SP: ${req.params.name}`);
|
||||
// logger.info(`Calling SP: ${req.params.name} by User: ${req.body.token || 'Guest'}`);
|
||||
|
||||
const result = await ormService.executeSp(req.params.name, params, req.params.dsNo);
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
logger.error(`API Error on ${req.params.name}: ${err.message}`);
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/upload/:dbname/:typeid', upload.single('file'), (req, res) => {
|
||||
if (!req.file) return res.status(400).json({ status: 400, msg: 'No file' });
|
||||
const fileUrl = `/static/upload/${req.params.dbname}/${req.params.typeid}/${req.file.filename}`;
|
||||
res.json({ status: 0, data: { value: fileUrl, url: fileUrl }, msg: 'success' });
|
||||
});
|
||||
|
||||
// 全域錯誤處理
|
||||
app.use((err, req, res, next) => {
|
||||
res.status(err.status || 500).json({ status: err.status || 500, msg: err.message });
|
||||
});
|
||||
|
||||
// --- Server 啟動邏輯 ---
|
||||
const HTTP_PORT = process.env.PORT || 5050;
|
||||
|
||||
// 啟動標準 HTTP
|
||||
http.createServer(app).listen(HTTP_PORT, () => {
|
||||
console.log(`?? HTTP Server running on http://localhost:${HTTP_PORT}`);
|
||||
});
|
||||
|
||||
// 根據 .env 決定是否啟動 HTTPS
|
||||
if (process.env.ENABLE_HTTPS === 'true') {
|
||||
try {
|
||||
const options = {
|
||||
key: fs.readFileSync(process.env.SSL_KEY_PATH),
|
||||
cert: fs.readFileSync(process.env.SSL_CRT_PATH)
|
||||
};
|
||||
const HTTPS_PORT = process.env.HTTPS_PORT || 5443;
|
||||
https.createServer(options, app).listen(HTTPS_PORT, () => {
|
||||
console.log(`?? HTTPS Server running on https://localhost:${HTTPS_PORT}`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('? Failed to start HTTPS server (Check SSL paths):', error.message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
require('dotenv').config();
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 15, // 增加併發處理能力
|
||||
queueLimit: 0,
|
||||
multipleStatements: true,
|
||||
timezone: '+08:00' // 強制時區一致
|
||||
});
|
||||
|
||||
// 啟動測試
|
||||
pool.getConnection()
|
||||
.then(conn => {
|
||||
console.log('✅ MariaDB Connected Successfully.');
|
||||
conn.release();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('❌ MariaDB Connection Failed:', err.message);
|
||||
});
|
||||
|
||||
module.exports = pool;
|
||||
@@ -0,0 +1,49 @@
|
||||
const nodemailer = require('nodemailer');
|
||||
const schedule = require('node-schedule');
|
||||
const db = require('../config/db');
|
||||
const logger = require('../utils/logger'); // 必須引入!
|
||||
|
||||
class MailService {
|
||||
constructor() {
|
||||
this.transporter = nodemailer.createTransport({
|
||||
host: "smtp.gmail.com",
|
||||
port: 465,
|
||||
secure: true,
|
||||
auth: { user: process.env.MAIL_USER, pass: process.env.MAIL_PASS }
|
||||
});
|
||||
}
|
||||
|
||||
async initAutoMail() {
|
||||
// 每 30 秒執行一次
|
||||
schedule.scheduleJob('*/30 * * * * *', async () => {
|
||||
try {
|
||||
// 增加一個簡單的連線檢查,避免資料庫掛掉時噴錯
|
||||
const [rows] = await db.query('SELECT * FROM zen_mail_list WHERE mail_status = 0 LIMIT 10');
|
||||
|
||||
if (rows.length > 0) {
|
||||
logger.info(`AutoMail: Processing ${rows.length} messages.`);
|
||||
}
|
||||
|
||||
for (let row of rows) {
|
||||
try {
|
||||
await this.transporter.sendMail({
|
||||
from: process.env.MAIL_USER,
|
||||
to: row.recipient,
|
||||
subject: row.mail_subject,
|
||||
html: row.content
|
||||
});
|
||||
await db.query('UPDATE zen_mail_list SET mail_status = 1, sent_at = NOW() WHERE id = ?', [row.id]);
|
||||
} catch (mailErr) {
|
||||
logger.error(`Mail ID ${row.id} failed: ${mailErr.message}`);
|
||||
await db.query('UPDATE zen_mail_list SET mail_status = 9, error_log = ? WHERE id = ?', [mailErr.message, row.id]);
|
||||
}
|
||||
}
|
||||
} catch (dbErr) {
|
||||
// 這裡現在可以正確使用 logger 了
|
||||
logger.error(`AutoMail Job DB Failure: ${dbErr.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new MailService();
|
||||
@@ -0,0 +1,516 @@
|
||||
/**
|
||||
* ORM Service for MariaDB
|
||||
* 功能:處理 amis 請求參數、解析核心 ORM 邏輯、呼叫 MariaDB Stored Procedures
|
||||
* Author: Senior Engineer Refactor
|
||||
*/
|
||||
|
||||
const db = require('../config/db');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
class OrmService {
|
||||
/**
|
||||
* 執行 Stored Procedure 並回傳 amis 指定格式
|
||||
* @param {string} spName - SP 名稱
|
||||
* @param {Array} params - 參數陣列
|
||||
* @param {number|string} dsNo - 回傳格式代號 (2, 3, 8, 20)
|
||||
*/
|
||||
async executeSp(spName, params, dsNo) {
|
||||
if (spName === "orm_api") {
|
||||
spName = "orm_api_v2"
|
||||
}
|
||||
|
||||
// 1. 強制確保 params 是陣列,避免 null.map 或 undefined.map 導致當機
|
||||
const safeParams = Array.isArray(params) ? params : [];
|
||||
|
||||
// MariaDB SP 呼叫語法: CALL sp_name(?, ?, ...)
|
||||
const placeholders = safeParams.map(() => '?').join(',');
|
||||
const sql = (safeParams.length > 0 || spName != "zen_null")
|
||||
? `CALL ${spName}(${placeholders})`
|
||||
: `CALL ${spName}()`; // 無參數時補上括號
|
||||
|
||||
// debug & hard code
|
||||
/*if (spName === "zen_null") {
|
||||
sql = `CALL ${spName}()`;
|
||||
}*/
|
||||
// 配合 amis 特殊執行 js 需透過呼叫 api, 當 dsNo=11 時,就直接 return
|
||||
if (dsNo === 11 || spName === "zen_null") {
|
||||
/*return {
|
||||
status: 0,
|
||||
code: 0,
|
||||
msg: 'ok',
|
||||
data: ''
|
||||
};*/
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- 除錯 Log 啟動 ---
|
||||
const startTime = Date.now();
|
||||
// 將參數轉為字串方便顯示,若是長字串(JSON)則截斷或完整呈現
|
||||
const paramsDebug = JSON.stringify(params);
|
||||
logger.info(`[SQL EXECUTE] Query: ${sql} | Params: ${paramsDebug}`);
|
||||
// --------------------
|
||||
|
||||
try {
|
||||
const [resultSets] = await db.query(sql, params);
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
// 取得結果集與狀態 (MariaDB 回傳格式處理)
|
||||
const status = resultSets[0] && resultSets[0][0] ? resultSets[0][0] : { code: 0, msg: 'Success', recno: 0 };
|
||||
const dataSet = resultSets[1] || [];
|
||||
|
||||
logger.info(`[SQL SUCCESS] SP: ${spName} | Time: ${duration}ms | Status: ${status.code}`);
|
||||
|
||||
// 根據 dsNo 格式化回傳內容給前端 amis
|
||||
const dsNoInt = parseInt(dsNo);
|
||||
switch (dsNoInt) {
|
||||
//新增 0,8,9 都是為了配合 amis 的格式需求, 0 是載入程式執行, 配合 genCode, 9 是為了顯示 json
|
||||
case 0: // CRUD 列表格式
|
||||
return {
|
||||
status: status.code,
|
||||
code: status.code,
|
||||
msg: status.msg,
|
||||
data: dataSet[0] ? (typeof dataSet[0].jsoncode === 'string' ? JSON.parse(dataSet[0].jsoncode) : dataSet[0].jsoncode) : {}
|
||||
};
|
||||
|
||||
case 1: // 原始結果集
|
||||
return resultSets;
|
||||
|
||||
case 3: // CRUD 列表格式
|
||||
return {
|
||||
status: status.code === 0 ? 0 : status.code,
|
||||
code: status.code === 0 ? 0 : status.code,
|
||||
msg: status.msg,
|
||||
data: {
|
||||
items: dataSet,
|
||||
total: status.recno || dataSet.length
|
||||
}
|
||||
};
|
||||
|
||||
case 5: // Get 使用, 固定回傳 xValue
|
||||
return {
|
||||
status: status.code,
|
||||
code: status.code,
|
||||
msg: status.msg,
|
||||
data: {
|
||||
"xValue": dataSet[0] ? dataSet[0].xValue : null
|
||||
}
|
||||
};
|
||||
|
||||
case 6: // 動態 options 回傳
|
||||
//const field6 = returnField || 'options';
|
||||
const field6 = 'options';
|
||||
return {
|
||||
status: status.code,
|
||||
code: status.code,
|
||||
msg: status.msg,
|
||||
data: {
|
||||
[field6]: dataSet[0] ? (typeof dataSet[0].jsoncode === 'string' ? JSON.parse(dataSet[0].jsoncode) : dataSet[0].jsoncode) : []
|
||||
}
|
||||
};
|
||||
|
||||
case 7: // Query Report 使用
|
||||
return {
|
||||
status: status.code,
|
||||
code: status.code,
|
||||
msg: status.msg,
|
||||
data: {
|
||||
"count": status.recno,
|
||||
"items": dataSet[0] ? (typeof dataSet[0].query === 'string' ? JSON.parse(dataSet[0].query) : dataSet[0].query) : []
|
||||
}
|
||||
};
|
||||
|
||||
case 8: // Options 選項格式 (Select/Checkboxes)
|
||||
return {
|
||||
status: 0,
|
||||
code: 0,
|
||||
msg: status.msg,
|
||||
data: { options: dataSet }
|
||||
};
|
||||
|
||||
case 9: // 動態 config 回傳
|
||||
//const field9 = returnField || 'config';
|
||||
const field9 = 'config';
|
||||
return {
|
||||
status: status.code,
|
||||
code: status.code,
|
||||
msg: status.msg,
|
||||
data: {
|
||||
[field9]: dataSet[0] ? (typeof dataSet[0].jsoncode === 'string' ? JSON.parse(dataSet[0].jsoncode) : dataSet[0].jsoncode) : {}
|
||||
}
|
||||
};
|
||||
|
||||
case 20: // 單筆資料格式 (Form Edit)
|
||||
return {
|
||||
status: 0,
|
||||
code: 0,
|
||||
msg: status.msg,
|
||||
data: dataSet[0] || {}
|
||||
};
|
||||
|
||||
case 2: // 標準格式
|
||||
default:
|
||||
return {
|
||||
status: 0,
|
||||
code: 0,
|
||||
msg: status.msg,
|
||||
recno: status.recno,
|
||||
data: dataSet
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(`[SQL ERROR] SP: ${spName} | Error: ${err.message} | Params: ${JSON.stringify(params)}`);
|
||||
return { status: 500, msg: `DB Error: ${err.message}`, data: null };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析核心 ORM 邏輯 (最佳化原本 index.js 內的字串切割部分)
|
||||
* 將 ^ 分隔符號轉換為 MariaDB 易於處理的 JSON 格式
|
||||
*/
|
||||
// 修改為接收 req 物件,以便抓取 IP
|
||||
prepareOrmPayload(req) {
|
||||
const body = req.body;
|
||||
let spName = req.params.name;
|
||||
|
||||
// --- 情況 A: 固定格式的 orm_api 或 checklogin ---
|
||||
if (spName === 'orm_api' || spName === 'orm_api_v2') {
|
||||
logger.info(`[MODE] Fixed Mapping for ${spName}`);
|
||||
spName = 'orm_api_v2';
|
||||
|
||||
// 呼叫 orm_kernel 取得處理後的 orm_data
|
||||
let ret_orm_data = this.orm_kernel(req);
|
||||
logger.info(`[ret_orm_data] ${ret_orm_data}`);
|
||||
|
||||
// 回傳 5 個參數給 CALL orm_api(?,?,?,?,?)
|
||||
return [
|
||||
body.token || '',
|
||||
body._$_tableName || '',
|
||||
body._$_pk || '',
|
||||
body._$_action || '',
|
||||
ret_orm_data // 這就是第 5 個參數 body.paras
|
||||
];
|
||||
}
|
||||
|
||||
// For Excel Import(TBD)
|
||||
if (spName === 'sys_excel_import') {
|
||||
const importDbname = req.body.db_name || dbname;
|
||||
const orm_table = req.body.table_name;
|
||||
const orm_pk = req.body.pk;
|
||||
const orm_action = 'C';
|
||||
const orm_data = JSON.stringify(req.body);
|
||||
|
||||
spName = 'orm_api_v2';
|
||||
|
||||
return [
|
||||
body.token || '',
|
||||
orm_table,
|
||||
orm_pk,
|
||||
orm_action,
|
||||
orm_data // 這就是第 5 個參數 body.paras
|
||||
];
|
||||
}
|
||||
|
||||
// --- 情況 B: 呼叫任意 SP (動態參數模式) ---
|
||||
// 排除所有系統保留字(以 _$_ 開頭或特定名稱),剩下的全部按順序傳入 SP
|
||||
// --- 1. 處理第一個固定參數: token ---
|
||||
const paraKeys = Object.keys(body).filter(key => {
|
||||
return key !== 'token' && !key.startsWith('_$_');
|
||||
});
|
||||
|
||||
// 字母排序確保順序一致 (para01 -> para02)
|
||||
paraKeys.sort();
|
||||
const orderedParas = paraKeys.map(key => body[key]);
|
||||
|
||||
// --- 2. 動態偵測是否有 token 參數 ---
|
||||
let finalParams = [];
|
||||
const hasToken = Object.prototype.hasOwnProperty.call(body, 'token');
|
||||
|
||||
if (hasToken) {
|
||||
// [模式 A] 有傳入 token:[token, para01, para02...]
|
||||
finalParams = [body.token || '', ...orderedParas];
|
||||
logger.info(`[PARAM_PREPARE] SP: ${spName} | Detected Token -> [token, ${paraKeys.join(', ')}]`);
|
||||
} else {
|
||||
// [模式 B] 沒有傳入 token:[para01, para02...]
|
||||
finalParams = [...orderedParas];
|
||||
logger.info(`[PARAM_PREPARE] SP: ${spName} | No Token Field -> [${paraKeys.join(', ')}]`);
|
||||
}
|
||||
|
||||
// 3. 統一進行空參數檢查 (防護機制)
|
||||
if (finalParams.length === 0) {
|
||||
finalParams = [];
|
||||
logger.warn(`[PARAM_CHECK] No parameters found for ${spName}. Array is empty.`);
|
||||
}
|
||||
|
||||
// 以下程式是因為 mariadb sp 的參數不支援 default, 為了防錯加入的 20250808
|
||||
// get_treedata 應傳入2個參數
|
||||
if (spName === 'get_treedata' || spName === 'get_assignData') {
|
||||
finalParams = [...orderedParas, "''"];
|
||||
}
|
||||
// get_treedata 應傳入3個參數
|
||||
//if (spName === 'zen_showsource') {
|
||||
// finalParams = [...orderedParas, "''"];
|
||||
//}
|
||||
|
||||
return finalParams;
|
||||
}
|
||||
|
||||
// null 回傳空白
|
||||
isnull(str) {
|
||||
// 檢查是否為 null, undefined 或空字串
|
||||
if (str === null || str === undefined || str === '') {
|
||||
return '';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
//先用 ~ 代替單引號, 在 orm_api 再 replace, 否則無法傳參
|
||||
quotstr2(str) {
|
||||
return '~' + str + '~';
|
||||
}
|
||||
|
||||
|
||||
//// copy from ms-sql version code 2026/01/04
|
||||
/**
|
||||
* 核心字串與物件處理邏輯
|
||||
* 本程式目前是完全照搬, 用 Gemini 優化都會有問題(轉換邏輯不全), 日後在想辦法優化
|
||||
*/
|
||||
orm_kernel(req) {
|
||||
let orm_pageNo = req.body.page || '1';
|
||||
let orm_perPage = req.body.perPage || '';
|
||||
let orm_keywords = req.body.keywords || '';
|
||||
let orm_keyfield = req.body._field_ || '';
|
||||
let orm_keyid = req.body._id_ || '';
|
||||
let orm_where = '';
|
||||
//
|
||||
let orm_table = req.body._$_tableName;
|
||||
let orm_pk = req.body._$_pk;
|
||||
let orm_action = req.body._$_action;
|
||||
let orm_data = '';
|
||||
//
|
||||
let i = 0;
|
||||
//
|
||||
let frmQ1 = '';
|
||||
let frmQ2 = '';
|
||||
let frmQ3 = '';
|
||||
let ret_sql= '';
|
||||
|
||||
//debug
|
||||
// console.log(req.body);
|
||||
// logger.info(`[PARAMS-orm_data] ${req.body}`);
|
||||
|
||||
/* orm 改用此種方式, 但 token 該如何處理 ??
|
||||
新機制: 加入 token, 為了限制查詢的標準功能
|
||||
*/
|
||||
//orm_table = req.body._$_tableName;
|
||||
if (req.body.token) {
|
||||
orm_table = req.body.token + '^' + req.body._$_tableName;
|
||||
} else {
|
||||
orm_table = req.body._$_tableName;
|
||||
}
|
||||
|
||||
orm_pk = req.body._$_pk;
|
||||
orm_action = req.body._$_action;
|
||||
|
||||
//debug
|
||||
//logger.info(`[debug-_query_filter] ${req.body._$_query_filter}`);
|
||||
|
||||
if (req.body._$_query_filter) {
|
||||
//換頁次
|
||||
if (req.body.page) {
|
||||
orm_pageNo = req.body.page;
|
||||
}
|
||||
if (req.body.perPage) {
|
||||
orm_perPage = req.body.perPage;
|
||||
}
|
||||
if (req.body.keywords) {
|
||||
orm_keywords = req.body.keywords;
|
||||
}
|
||||
// _id_ 是網址傳遞參數用, 當作 _query_filter 的第 9/10 個參數(where 的一部分)
|
||||
if (req.body._field_) {
|
||||
orm_keyfield = req.body._field_;
|
||||
}
|
||||
if (req.body._id_) {
|
||||
orm_keyid = req.body._id_;
|
||||
}
|
||||
|
||||
//debug
|
||||
logger.info(`[debug-_frmQueryFlds_] ${req.body._$_frmQueryFlds_}`);
|
||||
logger.info(`[debug-_frmQueryData_] ${req.body._$_frmQueryData_}`);
|
||||
logger.info(`[debug-_frmQueryType_] ${req.body._$_frmQueryType_}`);
|
||||
|
||||
/***********************************
|
||||
擴充 where 支援 Form Header 的多欄位查詢條件, 稍微複雜的表單, 應該都使用多欄位查詢, 而非單一 Query
|
||||
前端 post 進來時, 增加 3個 _$_開頭的變數
|
||||
req.body._$_frmQueryFlds_ exp: bildate^personid^productid
|
||||
req.body._$_frmQueryData_ exp: 20220101,20221231^A01^P001
|
||||
req.body._$_frmQueryType_ exp: C^C^C --> C=字串 要前後單引號 I=數字,不加單引號 C 和 I 後面可以加 command, 如 Clike 表示 %%, I>= 表示 >= 該值
|
||||
Michael 2022/4/23
|
||||
************************************/
|
||||
if (req.body._$_frmQueryFlds_) {
|
||||
frmQ1 = req.body._$_frmQueryFlds_;
|
||||
frmQ2 = req.body._$_frmQueryData_;
|
||||
frmQ3 = req.body._$_frmQueryType_;
|
||||
|
||||
// debug
|
||||
// console.log(frmQ2);
|
||||
|
||||
if (frmQ1 != '') {
|
||||
let qryArr1 = frmQ1.split("^");
|
||||
let qryArr2 = frmQ2.split("^");
|
||||
let qryArr3 = frmQ3.split("^");
|
||||
|
||||
for (i = 0; i < qryArr1.length; i++) {
|
||||
let v_filter = qryArr3[i].substring(1);
|
||||
if (qryArr3[i].substr(0, 1) == 'C') {
|
||||
if (qryArr2[i] != '' && qryArr2[i] != '0') {
|
||||
//if (qryArr2[i] != '') {
|
||||
//Date Range (between)
|
||||
let qryArr4 = qryArr2[i].split(",");
|
||||
if (qryArr4.length > 1) {
|
||||
orm_where = orm_where + qryArr1[i] + ' >= ' + this.quotstr2(qryArr4[0]) + ' and ' + qryArr1[i] + ' <= ' + this.quotstr2(qryArr4[1]) + (i == qryArr1.length - 1 ? '' : ' and ');
|
||||
}
|
||||
else if (v_filter == 'like') {
|
||||
orm_where = orm_where + qryArr1[i] + ' like ' + this.quotstr2('%' + qryArr2[i] + '%') + (i == qryArr1.length - 1 ? '' : ' and ');
|
||||
} else {
|
||||
orm_where = orm_where + qryArr1[i] + ' = ' + this.quotstr2(qryArr2[i]) + (i == qryArr1.length - 1 ? '' : ' and ');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (qryArr2[i] != '') {
|
||||
if (v_filter == '') {
|
||||
orm_where = orm_where + qryArr1[i] + '=' + qryArr2[i] + (i == qryArr1.length - 1 ? '' : ' and ');
|
||||
} else {
|
||||
orm_where = orm_where + qryArr1[i] + v_filter + qryArr2[i] + (i == qryArr1.length - 1 ? '' : ' and ');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//去掉後5碼的 and
|
||||
if (orm_where.substr(orm_where.length - 5, 5) == ' and ') {
|
||||
orm_where = orm_where.substr(0, orm_where.length - 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
/****************************************************/
|
||||
|
||||
orm_data = req.body._$_query_filter;
|
||||
const myArr = orm_data.split("^");
|
||||
//特別處理一下 orm_keywords, 1st=* 2st=myArr[7] 3st=非空的orm_keywords
|
||||
if (orm_keywords == '*') {
|
||||
orm_keywords = '';
|
||||
} else if (this.isnull(myArr[7]) != '') {
|
||||
//防錯(在特殊情況會誤傳, 在 ${ls:query_id} 機制)
|
||||
if (myArr[7] == '{$ls:token}') {
|
||||
orm_keywords = '';
|
||||
} else {
|
||||
orm_keywords = myArr[7];
|
||||
}
|
||||
}
|
||||
|
||||
// where keyword
|
||||
if (orm_where == '' || !orm_where) {
|
||||
orm_where = '';
|
||||
}
|
||||
|
||||
if (this.isnull(myArr[4]) != '' && orm_where == '') {
|
||||
orm_where = myArr[4];
|
||||
}
|
||||
|
||||
if (orm_perPage == '' || !orm_perPage) {
|
||||
orm_perPage = myArr[1];
|
||||
if (!orm_perPage) { orm_perPage = 10; }
|
||||
}
|
||||
|
||||
// 表單互 call 時, 傳遞參數也會借用此機制, 所以多加一個空值判斷 2023/1/28 Michael
|
||||
if (this.isnull(myArr[8]) != '' && this.isnull(myArr[9]) != '' && orm_keyfield == '' && orm_keyid == '') {
|
||||
orm_keyfield = myArr[8];
|
||||
orm_keyid = myArr[9];
|
||||
}
|
||||
|
||||
// debug to see the content
|
||||
// logger.info(`[PARAMS-orm_data] ${orm_data}`);
|
||||
|
||||
//前端傳入 sample: 1^10^functiontag^*^^^functiontag,tablename,fieldname^abc01^functiontag^abc01
|
||||
orm_data = orm_pageNo + '^' + orm_perPage + '^' + myArr[2] + '^' + myArr[3] + '^' + orm_where + '^' + this.isnull(myArr[5]) + '^' + this.isnull(myArr[6]) + '^' + orm_keywords + '^' + orm_keyfield + '^' + orm_keyid;
|
||||
} else //if (spName == 'orm_api') {
|
||||
{
|
||||
//專門處理 details 的 Object 問題(amis 的 joinValues Issue)
|
||||
/*
|
||||
if (req.body.details) {
|
||||
for (let i = 0; i < req.body.details.length; i++) {
|
||||
// 先 hard code productid, 確認無誤後, 再想辦法改為通用 20230828 Michael
|
||||
if (typeof req.body.details[i].productid === 'object' && req.body.details[i].productid.productid !== null) {
|
||||
req.body.details[i].productid = req.body.details[i].productid.productid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orm_api_v2 主要是改為用 parseJSON 分析傳入的 json
|
||||
主要是 amis 的 details 或是 picker 要多選取回時, json 的內容要在特殊處理
|
||||
改為 parseJSON 因為會寫入暫存, 相關比較好控制, 但還是要仔細測試過, 目前仍在測試中 20240127
|
||||
*/
|
||||
|
||||
// 先 hard code productid, 確認無誤後, 再想辦法改為通用 20230828 Michael (下列程式碼待測試中)
|
||||
let obj_id = {};
|
||||
let obj_id2 = '';
|
||||
let obj_id3 = {};
|
||||
//console.log(obj_id);
|
||||
//quickEdit donot execute
|
||||
console.log(Object.keys(req.body));
|
||||
console.log(req.body.hasOwnProperty("config"));
|
||||
if (Object.keys(req.body)[1] === 'rowsDiff' || Object.keys(req.body)[3] === 'rowsOrigin') {
|
||||
// break
|
||||
console.log('quickEdit');
|
||||
//} else if (Object.keys(req.body)[0] === 'config' || Object.keys(req.body)[6] === 'config') {
|
||||
} else if (req.body.hasOwnProperty("config") || req.body.hasOwnProperty("options")) {
|
||||
// break
|
||||
console.log('config-children or options');
|
||||
} else if (Object.keys(req.body)[0] === '0' || req.body._$_tableName === 'zen_fields') {
|
||||
// break
|
||||
console.log('zen_import_fields orm write error');
|
||||
} else {
|
||||
for (let i = 0; i < Object.keys(req.body).length; i++) {
|
||||
//console.log( Object.keys(req.body)[i]);
|
||||
|
||||
if (Object.keys(req.body)[i] == 'details') {
|
||||
//console.log( Object.keys(req.body.details));
|
||||
for (let j = 0; j < Object.keys(req.body.details).length; j++) {
|
||||
// 先 hard code productid, 確認無誤後, 再想辦法改為通用 20230828 Michael
|
||||
obj_id = req.body.details[Object.keys(req.body.details)[j]];
|
||||
//console.log(obj_id);
|
||||
for (let k = 0; k < Object.keys(obj_id).length; k++) {
|
||||
obj_id3 = obj_id[Object.keys(obj_id)[k]];
|
||||
if (typeof obj_id3 === 'object') {
|
||||
obj_id2 = Object.keys(obj_id3)[0];
|
||||
//console.log(obj_id2);
|
||||
if (obj_id2 !== null) {
|
||||
//console.log(obj_id2);
|
||||
req.body.details[j][obj_id2] = req.body.details[j][obj_id2][obj_id2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
obj_id = req.body[Object.keys(req.body)[i]];
|
||||
|
||||
if (typeof obj_id === 'object') {
|
||||
obj_id2 = Object.keys(obj_id)[0];
|
||||
//console.log(obj_id2);
|
||||
if (obj_id2 !== null) {
|
||||
//req.body[Object.keys(req.body)[i]] = req.body[Object.keys(req.body)[i]][obj_id2];
|
||||
req.body[obj_id2] = req.body[obj_id2][obj_id2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orm_data = JSON.stringify(req.body);
|
||||
}
|
||||
//
|
||||
return orm_data;
|
||||
}
|
||||
////
|
||||
}
|
||||
|
||||
module.exports = new OrmService();
|
||||
@@ -0,0 +1,32 @@
|
||||
const multer = require('multer');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
const { dbname, typeid } = req.params;
|
||||
const uploadPath = path.join(__dirname, `../../public/upload/${dbname}/${typeid}`);
|
||||
fs.mkdirSync(uploadPath, { recursive: true });
|
||||
cb(null, uploadPath);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const dateStr = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
cb(null, `${dateStr}-${file.originalname}`);
|
||||
}
|
||||
});
|
||||
|
||||
const upload = multer({
|
||||
storage,
|
||||
limits: { fileSize: parseInt(process.env.MAX_FILE_SIZE) || 50 * 1024 * 1024 },
|
||||
fileFilter: (req, file, cb) => {
|
||||
// 禁止上傳危險副檔名
|
||||
const forbiddenExtensions = ['.exe', '.sh', '.php', '.js', '.bat'];
|
||||
const ext = path.extname(file.originalname).toLowerCase();
|
||||
if (forbiddenExtensions.includes(ext)) {
|
||||
return cb(new Error('File type not allowed'), false);
|
||||
}
|
||||
cb(null, true);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = upload;
|
||||
@@ -0,0 +1,44 @@
|
||||
const winston = require('winston');
|
||||
require('winston-daily-rotate-file');
|
||||
const path = require('path');
|
||||
|
||||
const logFormat = winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf(info => `${info.timestamp} [${info.level.toUpperCase()}]: ${info.message}`)
|
||||
);
|
||||
|
||||
// 設定檔案滾動 (每天產生一個新檔,保留 14 天)
|
||||
const dailyRotateFileTransport = new winston.transports.DailyRotateFile({
|
||||
filename: 'logs/application-%DATE%.log',
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: logFormat
|
||||
});
|
||||
|
||||
const errorFileTransport = new winston.transports.DailyRotateFile({
|
||||
level: 'error',
|
||||
filename: 'logs/error-%DATE%.log',
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '30d',
|
||||
format: logFormat
|
||||
});
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
transports: [
|
||||
dailyRotateFileTransport,
|
||||
errorFileTransport,
|
||||
new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
logFormat
|
||||
)
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
module.exports = logger;
|
||||
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
|
||||
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
|
||||
GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
|
||||
YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
|
||||
MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
|
||||
BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
|
||||
GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
|
||||
BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
|
||||
3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
|
||||
YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
|
||||
rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
|
||||
ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
|
||||
oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
|
||||
QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
|
||||
b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
|
||||
AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
|
||||
GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
|
||||
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
|
||||
G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
|
||||
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
|
||||
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFgTCCBGmgAwIBAgIQOXJEOvkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7
|
||||
MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
|
||||
VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE
|
||||
AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4
|
||||
MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5
|
||||
MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO
|
||||
ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sI
|
||||
s9CsVw127c0n00ytUINh4qogTQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnG
|
||||
vDoZtF+mvX2do2NCtnbyqTsrkfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQ
|
||||
Ijy8/hPwhxR79uQfjtTkUcYRZ0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfb
|
||||
IWax1Jt4A8BQOujM8Ny8nkz+rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0
|
||||
tyA9yn8iNK5+O2hmAUTnAU5GU5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97E
|
||||
xwzf4TKuzJM7UXiVZ4vuPVb+DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNV
|
||||
icQNwZNUMBkTrNN9N6frXTpsNVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5
|
||||
D9kCnusSTJV882sFqV4Wg8y4Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJ
|
||||
WBp/kjbmUZIO8yZ9HE0XvMnsQybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ
|
||||
5lhCLkMaTLTwJUdZ+gQek9QmRkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzG
|
||||
KAgEJTm4Diup8kyXHAc/DVL17e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSg
|
||||
EQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rID
|
||||
ZsswDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAG
|
||||
BgRVHSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t
|
||||
L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr
|
||||
BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA
|
||||
A4IBAQAYh1HcdCE9nIrgJ7cz0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+
|
||||
rvSNb3I8QzvAP+u431yqqcau8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+
|
||||
/czSAaF9ffgZGclCKxO/WIu6pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gA
|
||||
CiIDEOUMsfnNkjcZ7Tvx5Dq2+UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1F
|
||||
zZOFli9d31kWTz9RvdVFGD/tSo7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyA
|
||||
vGp4z7h/jnZymQyd/teRCBaho1+V
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,37 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGizCCBPOgAwIBAgIRAMpp0hTVnTNA8nHekzJofCkwDQYJKoZIhvcNAQELBQAw
|
||||
YDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE3MDUGA1UE
|
||||
AxMuU2VjdGlnbyBQdWJsaWMgU2VydmVyIEF1dGhlbnRpY2F0aW9uIENBIERWIFIz
|
||||
NjAeFw0yNTA3MTUwMDAwMDBaFw0yNjA3MTUyMzU5NTlaMBkxFzAVBgNVBAMTDmFw
|
||||
aS5nZXguY29tLnR3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsofB
|
||||
Hrxs0VV2pATNZeawwqC5tvuRlhURnLcm9EC9YtiSeeKjukg4kZpr5+hKiNh6lsvW
|
||||
2smkLl37j+gTa0d7DMpUWNmEtmSUmMx0EvnWsDECIynW4PuZitjR/4VmeS9bxMI7
|
||||
hsa+kQGnzfjvvCkofhwWLYCw0h4en1tGAQq4TlGcP4wZeGfyjfbdpCRyd5wHNiE9
|
||||
F1Lh0S0URC+PLltOyQX2FaJLxUKnOrKLl5V7hQvgIDDPCAcySdWFcXAMmJpKeRHb
|
||||
L3ThdWBxPH4OcYs9GJsVAWcO+cV0f++sBTozt+TgnfLFU5oGONqNB349tUts6Zu0
|
||||
yg/KCGZTPHZvFXXjOQIDAQABo4IDBTCCAwEwHwYDVR0jBBgwFoAUaMASFhgOr872
|
||||
h6YyV6NGUV3LBycwHQYDVR0OBBYEFFK96TipyR8phtAVR1EiYOtdDfmBMA4GA1Ud
|
||||
DwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
|
||||
BgEFBQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEBAgIHMCUwIwYIKwYBBQUHAgEW
|
||||
F2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAECATCBhAYIKwYBBQUHAQEE
|
||||
eDB2ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29Q
|
||||
dWJsaWNTZXJ2ZXJBdXRoZW50aWNhdGlvbkNBRFZSMzYuY3J0MCMGCCsGAQUFBzAB
|
||||
hhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAtBgNVHREEJjAkgg5hcGkuZ2V4LmNv
|
||||
bS50d4ISd3d3LmFwaS5nZXguY29tLnR3MIIBfwYKKwYBBAHWeQIEAgSCAW8EggFr
|
||||
AWkAdwDYCVU7lE96/8gWGW+UT4WrsPj8XodVJg8V0S5yu0VLFAAAAZgMbNSkAAAE
|
||||
AwBIMEYCIQDGR0Nuw7OsH2o+TRAH7GwNPhkIe7lZWRs0ccnLIjgKcAIhANrIAcCy
|
||||
TkXkE4wHYKgrXJSKVI5jJMjMKul4gdcLIpWDAHYArKswcGzr7IQx9BPS9JFfER5C
|
||||
JEOx8qaMTzwrO6ceAsMAAAGYDGzUagAABAMARzBFAiB5nz6YPWn41YXMMArlvxPH
|
||||
m6o6CEK7Ai7HrYNU5HIZigIhAMJ4KTxfg+kR6MWqP83f9P15Qyw16iJm3hByObEM
|
||||
kV/yAHYA1219ENGn9XfCx+lf1wC/+YLJM1pl4dCzAXMXwMjFaXcAAAGYDGzUQwAA
|
||||
BAMARzBFAiBo3c0jrE1ri4XLwNX0pjiksWCBJt0zRlNVyhnfU1UhOQIhAOHt4Vnd
|
||||
mjno7yn7zUPOY95JrGXOYyCmA97qimNjAUL9MA0GCSqGSIb3DQEBCwUAA4IBgQCM
|
||||
w8XCex+oGGatwFLFzctyUSGZ6i/19T4Bk1CzBvscLsn1xe0eVvT8bkaBwuzFJQN0
|
||||
35q5FEXqIGlhsXIZYEeRAYe1xIHe8M03vWL8T1fPzqbCevSsZCOOljWOiaxeNAx9
|
||||
2AUlV/iORzfW1Pirj8XRUrvF15EQ8Fg0DPdOb8K8FfOkgEAubn6omTSimP0gTzF1
|
||||
KvMT87CqGuhIkr847/H+Hux7wpio4jy32QxMVIxVjUCP+Vp3QBPIjrErlfF9Qn8m
|
||||
S8OCgQn3CcZPCB9lsONRRhDEjkvGhUXdZWED7A1XlgGl9odavdwr5cMadujmE/Do
|
||||
XjlNod4V0C6sxH9JBfS/cV5scTzJZHuQs38h34FndVVQFgB9x2T1BVeDxrNeARJz
|
||||
lvnNYQ6jQyitkSmy2R1F2Eflml8wB3pS2xWfuGAPPfvqdEk6Hl+H0xzU+GzLq14A
|
||||
jZQt9wi59a8K47dcG/U0lT7nn5HdDbpj1xp7p6PJUPEsjCGsQ4BhKvUS8MyauUg=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,39 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG1TCCBL2gAwIBAgIQbFWr29AHksedBwzYEZ7WvzANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw
|
||||
MTMwMDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBLMQswCQYDVQQGEwJBVDEQMA4GA1UE
|
||||
ChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBSU0EgRG9tYWluIFNlY3VyZSBT
|
||||
aXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhmlzfqO1Mdgj
|
||||
4W3dpBPTVBX1AuvcAyG1fl0dUnw/MeueCWzRWTheZ35LVo91kLI3DDVaZKW+TBAs
|
||||
JBjEbYmMwcWSTWYCg5334SF0+ctDAsFxsX+rTDh9kSrG/4mp6OShubLaEIUJiZo4
|
||||
t873TuSd0Wj5DWt3DtpAG8T35l/v+xrN8ub8PSSoX5Vkgw+jWf4KQtNvUFLDq8mF
|
||||
WhUnPL6jHAADXpvs4lTNYwOtx9yQtbpxwSt7QJY1+ICrmRJB6BuKRt/jfDJF9Jsc
|
||||
RQVlHIxQdKAJl7oaVnXgDkqtk2qddd3kCDXd74gv813G91z7CjsGyJ93oJIlNS3U
|
||||
gFbD6V54JMgZ3rSmotYbz98oZxX7MKbtCm1aJ/q+hTv2YK1yMxrnfcieKmOYBbFD
|
||||
hnW5O6RMA703dBK92j6XRN2EttLkQuujZgy+jXRKtaWMIlkNkWJmOiHmErQngHvt
|
||||
iNkIcjJumq1ddFX4iaTI40a6zgvIBtxFeDs2RfcaH73er7ctNUUqgQT5rFgJhMmF
|
||||
x76rQgB5OZUkodb5k2ex7P+Gu4J86bS15094UuYcV09hVeknmTh5Ex9CBKipLS2W
|
||||
2wKBakf+aVYnNCU6S0nASqt2xrZpGC1v7v6DhuepyyJtn3qSV2PoBiU5Sql+aARp
|
||||
wUibQMGm44gjyNDqDlVp+ShLQlUH9x8CAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaA
|
||||
FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTI2XhootkZaNU9ct5fCj7c
|
||||
tYaGpjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE
|
||||
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQIC
|
||||
TjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1
|
||||
c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG
|
||||
CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu
|
||||
Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
|
||||
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAVDwoIzQDV
|
||||
ercT0eYqZjBNJ8VNWwVFlQOtZERqn5iWnEVaLZZdzxlbvz2Fx0ExUNuUEgYkIVM4
|
||||
YocKkCQ7hO5noicoq/DrEYH5IuNcuW1I8JJZ9DLuB1fYvIHlZ2JG46iNbVKA3ygA
|
||||
Ez86RvDQlt2C494qqPVItRjrz9YlJEGT0DrttyApq0YLFDzf+Z1pkMhh7c+7fXeJ
|
||||
qmIhfJpduKc8HEQkYQQShen426S3H0JrIAbKcBCiyYFuOhfyvuwVCFDfFvrjADjd
|
||||
4jX1uQXd161IyFRbm89s2Oj5oU1wDYz5sx+hoCuh6lSs+/uPuWomIq3y1GDFNafW
|
||||
+LsHBU16lQo5Q2yh25laQsKRgyPmMpHJ98edm6y2sHUabASmRHxvGiuwwE25aDU0
|
||||
2SAeepyImJ2CzB80YG7WxlynHqNhpE7xfC7PzQlLgmfEHdU+tHFeQazRQnrFkW2W
|
||||
kqRGIq7cKRnyypvjPMkjeiV9lRdAM9fSJvsB3svUuu1coIG1xxI1yegoGM4r5QP4
|
||||
RGIVvYaiI76C0djoSbQ/dkIUUXQuB8AL5jyH34g3BZaaXyvpmnV4ilppMXVAnAYG
|
||||
ON51WhJ6W0xNdNJwzYASZYH+tmCWI+N60Gv2NNMGHwMZ7e9bXgzUCZH5FaBFDGR5
|
||||
S9VWqHB73Q+OyIVvIbKYcSc2w/aSuFKGSA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,37 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGbDCCBFSgAwIBAgIRAP+xCJvA5ssP/6EmqA7p960wDQYJKoZIhvcNAQEMBQAw
|
||||
SzELMAkGA1UEBhMCQVQxEDAOBgNVBAoTB1plcm9TU0wxKjAoBgNVBAMTIVplcm9T
|
||||
U0wgUlNBIERvbWFpbiBTZWN1cmUgU2l0ZSBDQTAeFw0yMzA0MzAwMDAwMDBaFw0y
|
||||
MzA3MjkyMzU5NTlaMBkxFzAVBgNVBAMTDmFwaS5nZXguY29tLnR3MIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqrhI+MLi+rsUSGlPHIrPnJ4+SGnntnQn
|
||||
6W1xbd5go2FOiU1Z0d8gfIo4acH9qO6sFSL8MwjREkeG2szHSoOONx2dDll+bioq
|
||||
c5QrB0PsdRUgEX+xlvHgIbJjm4xiSgGVhlDAoK9fc9E+UMQa7uRIy01X8zjqYoNo
|
||||
rgGlF6Nf4ffpedK48A9oflIiN1VsgsQLRR3yJlG7qaFR78qJd8aH9U+feZ9H/fIW
|
||||
F9iOAEI0+Zpz6nRzc0zqinap4/+Gas+MSRcGkptX6Znw+NwVKMdPkSTmDSyXswU1
|
||||
5Ns4wjCF2EqnAbMbuQqbOkV8c3AqwL/pZnadNVacW5s6NwRJpX16EwIDAQABo4IC
|
||||
ezCCAncwHwYDVR0jBBgwFoAUyNl4aKLZGWjVPXLeXwo+3LWGhqYwHQYDVR0OBBYE
|
||||
FAuVtNojbIzcY48XCw9/6Pmy03KaMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8E
|
||||
AjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBJBgNVHSAEQjBAMDQG
|
||||
CysGAQQBsjEBAgJOMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20v
|
||||
Q1BTMAgGBmeBDAECATCBiAYIKwYBBQUHAQEEfDB6MEsGCCsGAQUFBzAChj9odHRw
|
||||
Oi8vemVyb3NzbC5jcnQuc2VjdGlnby5jb20vWmVyb1NTTFJTQURvbWFpblNlY3Vy
|
||||
ZVNpdGVDQS5jcnQwKwYIKwYBBQUHMAGGH2h0dHA6Ly96ZXJvc3NsLm9jc3Auc2Vj
|
||||
dGlnby5jb20wggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdwCt9776fP8QyIudPZwe
|
||||
PhhqtGcpXc+xDCTKhYY069yCigAAAYfRcwfDAAAEAwBIMEYCIQDocC5ZkoSr0GWX
|
||||
GuLPEosM2pbIkYLyQz3EmEHNQUwdQQIhAOr+1q3jIRN1IxG8LMKwkB8Y71Oeisos
|
||||
IiyaRmBD4NADAHYAejKMVNi3LbYg6jjgUh7phBZwMhOFTTvSK8E6V6NS61IAAAGH
|
||||
0XMIHAAABAMARzBFAiEAssoYv0oEVSZraxpPjdyg29pNLREQcodN68Fl2Gy/+t8C
|
||||
IBH8Z0ohdsXlfBzqI0PaylUK3+QmR7Gl67lkz/9QxlYyMBkGA1UdEQQSMBCCDmFw
|
||||
aS5nZXguY29tLnR3MA0GCSqGSIb3DQEBDAUAA4ICAQByseVToYNy2DQgKfhA4uom
|
||||
PDYbfYjfQT5xPlIk2JiXfeB34JxjVtO77hw4gfMlVi+TdzBj7tKzuz0V+pL4MhiW
|
||||
hsHUwPtNZGUSdFAdLGlEE1x6s+Js38+nXTSiG+SDXGyOwQeoXDJtckOX03N1/CKa
|
||||
/FM2T2HbyWziiW6erzHekkRrzOEXgQRt/b3pA1EYhj5bhG+bLmEDmfkeot0y2BvP
|
||||
rBhkgcwpPqut7y0Jhfdo5KgBbWGYPjjWUQOzwldQMjovRnA0m77A5OpDZwOwfpbE
|
||||
KhCK8sj5OQFKAC7SHLPmLkCRhW55OsSlRt+3o8szO/MfO51otR8kbtkbbYJcLRFq
|
||||
6g7lVXGiVYEl63P+L/QqIZli8YUk0XijDIf9CZlbS/ZB41PKxJT3z/XrOrrkmaF+
|
||||
QZFDOya4CBIeBdBAJcVkwf+rV1JvmYxxKSu0VHRiPSugwqT9TokOWUFUlJKapFu9
|
||||
w3/JOlfeLgucH8M4tcwnmTyBQAkSSr8gSLgyVOLI+78z8YiLBSpnUYJ1tE4iw7WB
|
||||
fjSN0V6wCO9iijbeMoZ56qO8bcbL+iRCSSKfjJFL77OegV6sZGqcrZ04zXD/7rAp
|
||||
u6AytbEfxvrKE6xC3jJzUdVO7wstOBUcGaliVQ8bcFthU3XRYT/SI1CgsKCsbHQD
|
||||
BNXcZTV0CZQEul/CRxyBqA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAqrhI+MLi+rsUSGlPHIrPnJ4+SGnntnQn6W1xbd5go2FOiU1Z
|
||||
0d8gfIo4acH9qO6sFSL8MwjREkeG2szHSoOONx2dDll+bioqc5QrB0PsdRUgEX+x
|
||||
lvHgIbJjm4xiSgGVhlDAoK9fc9E+UMQa7uRIy01X8zjqYoNorgGlF6Nf4ffpedK4
|
||||
8A9oflIiN1VsgsQLRR3yJlG7qaFR78qJd8aH9U+feZ9H/fIWF9iOAEI0+Zpz6nRz
|
||||
c0zqinap4/+Gas+MSRcGkptX6Znw+NwVKMdPkSTmDSyXswU15Ns4wjCF2EqnAbMb
|
||||
uQqbOkV8c3AqwL/pZnadNVacW5s6NwRJpX16EwIDAQABAoIBAHqR9ypLWgWkfaqD
|
||||
mV4nt2l+H7+D8e4INYOdpRu51m5W9bkUhRFufneMEXa05fb87SX7yVCm2tyh6At9
|
||||
jPRNwbSGmXVtAZ38vh/fWIlN1h41vaFyqcFzBXWMC4HpZ8Q0oPMfVT3Iy+Jub6wz
|
||||
MBcmZbE5ZZTl3zo9mNGdsrdm//dPBUvXFHPljRYJRgK8ZMD0NK+eWn7ynzYPtHBu
|
||||
U/djjCUqoUGVokXPymdCc/FfD9FdLJo7d9b3udShrELCZA3nrk+COmgGFgoEiz7n
|
||||
QDAG0MNMtRL3BXrpDkxoB3ZIQpe1eI996axRffdAPMOOGrNNLb/90IwTI4ZzaCgx
|
||||
TWnF/pkCgYEA7pclED+YDBXz8f6D2UkA9P4UFv3c+JIdTHZ+vvyisTMJdEbgHgfy
|
||||
NvzwYm+nHvbestb0sFV3X6y7LA5WetxeX0f7iCUSwo1/GmgO9u6QA5b1h758BZhh
|
||||
auhhHq5GRwi4M3Ddzo5KzmBFCvt4jW8EM8Ahv+fujhNPGCaFc1LSIMcCgYEAty1S
|
||||
hUgTdwECbmBLQi9Wg9DGPSBooOYhlJ9kll3I5oydLHb5LxxfSfLi17g4JXRVr/aJ
|
||||
uUFzf0aLUgYiGH+H2I2cH2qAGeCw3P/gFXHUntUqBKb9yEb3rngahVViV+zWTPQY
|
||||
gPSbscDC51jtzbkFBx4RF65v6Kr24T2xrrQaqFUCgYEAwsMK9FqVSbhZ7H8xLhxT
|
||||
9am6yJHu4dKUrChGiq08OZ5J52s75Afkh1KvAAvYxoQLgr3J/G+oBKfCGtKRcbWW
|
||||
K/1crORmjf5ndSzgml5fnS6Lu4WZRBAB5f1P2nW01KOfig5mYgjxs8oOUkq5O+sV
|
||||
6RC7/CXeLIhClppLcbp34V0CgYEAqYJodexADwVBIbE8k6/IyMyfVpuyFws/khB6
|
||||
feel7Su8mxQx/hWsXHtGzkestYRVczObOXNHFUXL0YjZboA9zvkku7HLf6b9JFYp
|
||||
IM8o6h7q9kkuWnLJ64s7R52/FwyVN7s/Hb6+gZyXAI276n9IFtENEjQbXV0wfzmf
|
||||
PsNuU80CgYAIrPJMTa3jTQyrq7Rl5KNQLvn5ciUmi2yM0sH6zDnYv0KDd/rbl2LB
|
||||
KgrYI/UAzBySzmls/5Oxw0/2hyW+x7HQGSwgganUQ8o9f8t5lXwU+v6609adnHkN
|
||||
GJV+CShfoDI9oIAIT/KehwC3V1tGcqkl2qYG3bWyAdfvuRpMviCrJw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCyh8EevGzRVXak
|
||||
BM1l5rDCoLm2+5GWFRGctyb0QL1i2JJ54qO6SDiRmmvn6EqI2HqWy9bayaQuXfuP
|
||||
6BNrR3sMylRY2YS2ZJSYzHQS+dawMQIjKdbg+5mK2NH/hWZ5L1vEwjuGxr6RAafN
|
||||
+O+8KSh+HBYtgLDSHh6fW0YBCrhOUZw/jBl4Z/KN9t2kJHJ3nAc2IT0XUuHRLRRE
|
||||
L48uW07JBfYVokvFQqc6souXlXuFC+AgMM8IBzJJ1YVxcAyYmkp5EdsvdOF1YHE8
|
||||
fg5xiz0YmxUBZw75xXR/76wFOjO35OCd8sVTmgY42o0Hfj21S2zpm7TKD8oIZlM8
|
||||
dm8VdeM5AgMBAAECggEAYOLHbVS4gUouHoj0pu5w0s7Cuoj/00EP08qZe0h+/tul
|
||||
cjwKupdjC7GQCcTIXkeND7UDnqx7SyZ51PkPQNMD9kb/S1CQcyNWeS3LeFjZp7iQ
|
||||
/mBAWsxv4SgVnuPYXr/Sv47hGx1UYgFR/bew8p4reXTonD0QuJbb64NvFDWrG+TJ
|
||||
vG6lLuJ6UIjD/b7Xrm+SewmTCU4vo/ItQATmuMisDmqYbQsqfjyZO6FXl7kGCkbD
|
||||
g9zSEiq9PzX9kf+fQpHBYSNi8vkxvkSzjPgX/kNG7rHPM0r66S1hKi1KhuFgiEdq
|
||||
5YUrnFme0eGeg3aOyQrNDGCNjcoXELJvksw5DdAh2QKBgQDjN0Qpsy4wYJdvQj0T
|
||||
G3/Yuo0R8LCHfj6ba+WQn1sLKLFywHwfiFlJXXBAKLVK919414E0CHlhN14SMTp6
|
||||
DRHbFEqfk06OCfxi7Q41UJEJey7phbB//4Ak24NBba20Pk2qhycyWiuae9HTK2LW
|
||||
fATxsUD3zQtcJv/m6U5s4YZbpwKBgQDJJZaKT/l5Bmj4x5qanjTZbZmfwBWVjBWE
|
||||
6DlcptDlYjyJuhhe30YM6kwh79Qgsb5T42jHW+HzJbRwgFV2469yssEvnZ32xa2M
|
||||
MHWzR57wL3KpwUldeCyP843ELPaVqUxyEcj12RM+d6EAa4nuohu5qRcxmyScrOqs
|
||||
1nnZgXomHwKBgDFz/en1jcAJxev5RsG54oGRWNLmyAU1fPrm6PgpNu+e08BeFKXo
|
||||
T0agh6XvNkYywRzUCtMAZSq7mkXrYQbfgVtldzh0H0za74u4fLct6eNeZD9/UYMK
|
||||
YSGkhVTgQkZQqSbMc8OJzKO6/1guwTxdkdXo9nL4tdhAxMHFVcRs8YlRAoGAMiqO
|
||||
vhYuGRIRMiLOG0vj0Gp2SxJkD7UtVMV6MPJl3R/AC3V/SIIU/Xmd3UTsOe86kb+A
|
||||
zV/MHZFEzF4lco5cnpWYeuCrmfU5UGJxqHHvYOXkihPr0UT8kDZlIA06vp7Hsxde
|
||||
cHpgQ08gt3MapoqFsatLXpLb8btqmAqxvx58sW8CgYBqrO1Uw3h0TBDiRhr3rUi0
|
||||
AH08GHIDqGFdMDLM6FJuiFX+MEH6NdLIW+zZTLkO9JFGKXsjBpoSewZt09di+E2b
|
||||
97xAnc5qvzlx4JNBahWjghp6kRZrIC0mFVQ+7VWvlFyiH8q+E6BRqxGpz5A3xdI7
|
||||
DMGXTmNW+7LfmQZ6aNErsw==
|
||||
-----END PRIVATE KEY-----
|
||||