6 Commits
2.0.0 ... 2.1.1

Author SHA1 Message Date
putyy
37424da698 更新版本号 2024-09-03 16:02:56 +08:00
putyy
7fd4877087 升级openssl、linux测试版本 2024-09-03 15:59:48 +08:00
putyy
619ac47962 更新配置 2024-08-30 20:43:12 +08:00
putyy
6b79585564 内置aria2下载、增加视频号画质设置、取消重复下载限制、优化下载命名等 2024-08-30 20:40:10 +08:00
putyy
c1f05876e3 优化拦截规则 2024-08-19 16:55:52 +08:00
putyy
2981518cf4 Update README.md 2024-07-24 09:47:48 +08:00
65 changed files with 1124 additions and 329 deletions

View File

@@ -1,5 +1,6 @@
# V2.0重磅更新,所见即所得!
## res-downloader(爱享素材下载器)
## res-downloader(爱享素材下载器) 【[点击加入群聊](https://qm.qq.com/q/W8mVeZideE)】
🎯 基于 [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue.git)
📦 操作简单、可获取不同类型的资源
🖥️ 支持Win10、Win11、Mac
🌐 支持视频、音频、图片、m3u8等网络资源下载
💪 支持微信视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐等网络资源下载
@@ -38,8 +39,25 @@ Win7无法使用
>> MAC: /Users/你的用户名称/.res-downloader@putyy/res-downloader-installed.lock
>> Win: C:\Users\Admin\.res-downloader@putyy/res-downloader-installed.lock
#### 更多问题见: [issues](https://github.com/putyy/res-downloader/issues)、[爱享论坛](https://s.gowas.cn/d/4089-quan-ping-tai-zi-yuan-xia-zai-ruan-jian-zui-xin-ban-v106/171)
其他问题请留言 https://github.com/putyy/res-downloader/issues
## 二次开发
> ps 打包慢的问题可以参考 https://www.putyy.com/articles/87
```sh
git clone https://github.com/putyy/res-downloader
cd res-downloader
yarn install
yarn run dev
# 打包mac
yarn run build --universal --mac
# 打包win
yarn run build --win
```
## 免责声明
本软件用于学习研究使用,若因使用本软件造成的一切法律责任均与本人无关!
```

3
components.d.ts vendored
View File

@@ -15,10 +15,13 @@ declare module 'vue' {
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElLink: typeof import('element-plus/es')['ElLink']
ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
Footer: typeof import('./src/components/layout/Footer.vue')['default']
Index: typeof import('./src/components/layout/Index.vue')['default']

View File

@@ -3,7 +3,7 @@
*/
{
"$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json",
"appId": "com.putyy.ResDownloader",
"appId": "com.putyy.res-downloader",
"asar": true,
"directories": {
"output": "release/${version}"
@@ -14,7 +14,7 @@
"electron/res/**/*"
],
"mac": {
"icon": "electron/res/icon/icons/mac/icon.icns",
"icon": "electron/res/icon/mac.icns",
"artifactName": "${productName}_${version}.${arch}.${ext}",
"singleArchFiles": "*",
"target": [
@@ -22,13 +22,62 @@
"target": "dmg",
"arch": [
'x64',
'arm64'
'arm64',
'universal'
]
}
],
"extraResources": [
{
"from": "electron/res/darwin/aria2/aria2.conf",
"to": "electron/res/darwin/aria2/aria2.conf",
"filter": ["**/*"]
},
{
"from": "electron/res/darwin/aria2/${arch}/aria2c",
"to": "electron/res/darwin/aria2/aria2c",
"filter": ["**/*"],
}
]
},
"linux": {
"icon": "electron/res/icon/icon.png",
"artifactName": "${productName}_${version}.${arch}.${ext}",
"category": "Network",
"target": [
{
"target": "AppImage",
"arch": [
"x64",
"arm64",
"armv7l"
]
},
{
"target": "deb",
"arch": [
"x64",
"arm64",
"armv7l"
]
}
],
"extraResources": [
{
"from": "electron/res/linux/aria2/aria2.conf",
"to": "electron/res/linux/aria2/aria2.conf",
"filter": ["**/*"]
},
{
"from": "electron/res/linux/aria2/${arch}/aria2c",
"to": "electron/res/linux/aria2/aria2c",
"filter": ["**/*"],
}
]
},
"win": {
"icon": "electron/res/icon/icons/win/icon.ico",
"icon": "electron/res/icon/win.ico",
"artifactName": "${productName}_${version}.${ext}",
"target": [
{
"target": "nsis",
@@ -37,7 +86,13 @@
]
}
],
"artifactName": "${productName}_${version}.${ext}"
"extraResources": [
{
"from": "electron/res/win",
"to": "electron/res/win",
"filter": ["**/*"],
}
]
},
"nsis": {
"oneClick": false,
@@ -47,6 +102,7 @@
"deleteAppDataOnUninstall": false
},
"extraResources": [
"electron/res"
"electron/res/icon",
"electron/res/keys",
]
}

51
electron/main/aria2Rpc.ts Normal file
View File

@@ -0,0 +1,51 @@
const axios = require('axios')
import CONFIG from './const'
export class Aria2RPC {
constructor() {
this.url = `http://127.0.0.1:${CONFIG.ARIA_PORT}/jsonrpc`
this.id = 1
}
call(method, params) {
const requestData = {
jsonrpc: "2.0",
method: method,
params: params,
id: this.id++
};
return axios.post(this.url, requestData, {
headers: {
'Content-Type': 'application/json'
},
}).then((response)=>{
return response.data
})
}
addUri(uri, dir, filename, headers = {}) {
return this.call('aria2.addUri', [uri, {
dir: dir,
out: filename,
headers: headers,
}]);
}
tellStatus(gid) {
return this.call('aria2.tellStatus', [gid]);
}
calculateDownloadProgress(bitfield) {
// 将十六进制的 bitfield 转换为二进制字符串
const totalPieces = bitfield.length * 4; // 每个十六进制字符对应 4 位
const binaryString = bitfield.split('').map(hex => parseInt(hex, 16).toString(2).padStart(4, '0')).join('');
// 计算已下载的部分数
const downloadedPieces = binaryString.split('').filter(bit => bit === '1').length;
// 计算进度百分比
const progressPercentage = (downloadedPieces / totalPieces) * 100;
return progressPercentage.toFixed(2); // 保留两位小数
}
}

View File

@@ -21,10 +21,22 @@ export async function installCert(checkInstalled = true) {
`echo "输入本地登录密码" && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${CONFIG.CERT_PUBLIC_PATH}" && touch ${CONFIG.INSTALL_CERT_FLAG} && echo "安装完成"`,
)
dialog.showMessageBoxSync({
type: 'info',
type: "info",
message: `命令已复制到剪贴板,粘贴命令到终端并运行以安装并信任证书`,
});
reject()
});
} else if (process.platform === 'linux') {
return new Promise((resolve, reject) => {
clipboard.writeText(
"https://github.com/putyy/res-downloader/blob/master/electron/res/keys/public.pem",
)
dialog.showMessageBoxSync({
type: "info",
message: `Linux系统请手动安装证书已复制下载地址`,
});
reject()
});
} else {

View File

@@ -17,13 +17,14 @@ export default {
IS_DEV: isDev,
EXECUTABLE_PATH,
HOME_PATH,
APP_CN_NAME: '爱享素材下载器',
APP_EN_NAME: 'ResDownloader',
CERT_PRIVATE_PATH: path.join(EXECUTABLE_PATH, './keys/private.pem'),
CERT_PUBLIC_PATH: path.join(EXECUTABLE_PATH, './keys/public.pem'),
INSTALL_CERT_FLAG: path.join(HOME_PATH, './res-downloader-installed.lock'),
WIN_CERT_INSTALL_HELPER: path.join(EXECUTABLE_PATH, './w_c.exe'),
APP_CN_NAME: '爱享素材下载器',
APP_EN_NAME: 'ResDownloader',
REGEDIT_VBS_PATH: path.join(EXECUTABLE_PATH, './regedit-vbs'),
OPEN_SSL_BIN_PATH: path.join(EXECUTABLE_PATH, './openssl/openssl.exe'),
OPEN_SSL_CNF_PATH: path.join(EXECUTABLE_PATH, './openssl/openssl.cnf'),
WIN_CERT_INSTALL_HELPER: path.join(EXECUTABLE_PATH, './win/w_c.exe'),
REGEDIT_VBS_PATH: path.join(EXECUTABLE_PATH, './win/regedit-vbs'),
OPEN_SSL_BIN_PATH: path.join(EXECUTABLE_PATH, './win/openssl/openssl.exe'),
OPEN_SSL_CNF_PATH: path.join(EXECUTABLE_PATH, './win/openssl/openssl.cnf'),
ARIA_PORT: "18899",
};

View File

@@ -3,6 +3,10 @@ import {release} from 'node:os'
import {join} from 'node:path'
import CONFIG from './const'
import initIPC, {setWin} from './ipc'
import {closeProxy} from "./setProxy"
import log from "electron-log"
import path from 'path'
import {spawn} from 'child_process'
// The built directory structure
//
@@ -45,6 +49,7 @@ process.on('unhandledRejection', () => {
let mainWindow: BrowserWindow | null = null
let previewWin: BrowserWindow | null = null
let aria2Process
// Here, you can also use other preload
const preload = join(__dirname, '../preload/index.js')
@@ -77,21 +82,16 @@ app.on('activate', () => {
}
})
// New window example arg: new windows url
ipcMain.handle('open-win', (_, arg) => {
const childWindow = new BrowserWindow({
webPreferences: {
preload,
nodeIntegration: true,
contextIsolation: false,
},
})
if (process.env.VITE_DEV_SERVER_URL) {
childWindow.loadURL(`${url}#${arg}`)
} else {
childWindow.loadFile(indexHtml, {hash: arg})
app.on('before-quit', async e => {
e.preventDefault()
try {
await closeProxy()
aria2Process && aria2Process.kill();
log.log("--------------closeProxy success--------------")
} catch (error) {
log.log("--------------proxy catch err--------------", error)
}
app.exit()
})
function createWindow() {
@@ -169,9 +169,45 @@ function createPreviewWindow(parent: BrowserWindow) {
})
}
function createAria2Process() {
// 根据操作系统选择 aria2 的路径
try {
let aria2Path, aria2Conf
if (process.platform === 'win32') {
// Windows
aria2Path = path.join(CONFIG.EXECUTABLE_PATH, "./win/aria2/aria2c.exe")
aria2Conf = path.join(CONFIG.EXECUTABLE_PATH, "./win/aria2/aria2.conf")
} else {
aria2Path = path.join(CONFIG.EXECUTABLE_PATH, `./${process.platform}/aria2` + (CONFIG.IS_DEV ? `/${process.arch}` : '/') + "/aria2c");
aria2Conf = path.join(CONFIG.EXECUTABLE_PATH, `./${process.platform}/aria2/aria2.conf`)
}
// 启动 aria2
console.log("启动 aria2")
aria2Process = spawn(aria2Path, [`--conf-path=${aria2Conf}`, `--rpc-listen-port=${CONFIG.ARIA_PORT}`], {
windowsHide: false,
stdio: CONFIG.IS_DEV ? 'pipe' : 'ignore'
});
if(!aria2Process){
console.log("启动 aria2 失败")
}
if (CONFIG.IS_DEV) {
aria2Process.stdout.on('data', (data) => {
console.log(`aria2: ${data}`);
});
aria2Process.stderr.on('data', (data) => {
console.log(`aria2 error: ${data}`);
});
}
console.log("aria2 成功启动")
} catch (e) {
console.log(`aria2 process start err`, e);
}
}
app.whenReady().then(() => {
initIPC()
createWindow()
createPreviewWindow(mainWindow)
createAria2Process()
setWin(mainWindow, previewWin)
})
})

View File

@@ -1,26 +1,27 @@
import {ipcMain, dialog, BrowserWindow, app, shell} from 'electron'
import {startServer} from './proxyServer'
import {installCert, checkCertInstalled} from './cert'
import {downloadFile, decodeWxFile, suffix} from './utils'
import {decodeWxFile, suffix, getCurrentDateTimeFormatted} from './utils'
// @ts-ignore
import {hexMD5} from '../../src/common/md5'
import {Aria2RPC} from './aria2Rpc'
import fs from "fs"
import {floor} from "lodash"
let win: BrowserWindow
let previewWin: BrowserWindow
let isStartProxy = false
const aria2RpcClient = new Aria2RPC()
export default function initIPC() {
ipcMain.handle('invoke_app_is_init', async (event, arg) => {
// 初始化应用 安装证书相关
return checkCertInstalled()
})
ipcMain.handle('invoke_init_app', (event, arg) => {
ipcMain.handle('invoke_init_app', (event, arg) => {
// 开始 初始化应用 安装证书相关
installCert(false).then(r => {})
installCert(false).then(r => {
})
})
ipcMain.handle('invoke_start_proxy', (event, arg) => {
@@ -33,7 +34,7 @@ export default function initIPC() {
win: win,
upstreamProxy: arg.upstream_proxy ? arg.upstream_proxy : "",
setProxyErrorCallback: err => {
console.log('setProxyErrorCallback', err)
},
})
})
@@ -63,33 +64,77 @@ export default function initIPC() {
return {is_file: res, fileName: `${save_path}/${fileName}.mp4`}
})
ipcMain.handle('invoke_down_file', async (event, {data, save_path}) => {
ipcMain.handle('invoke_down_file', async (event, {data, save_path, quality}) => {
let down_url = data.url
if (!down_url) {
return false
return new Promise((resolve, reject) => {
resolve(false);
});
}
if (quality !== "-1" && data.decode_key && data.file_format) {
const format = data.file_format.split('#');
const qualityMap = [
format[0],
format[Math.floor(format.length / 2)],
format[format.length - 1]
];
down_url += "&X-snsvideoflag=" + qualityMap[quality];
}
let fileName = data?.description ? data.description.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '') : hexMD5(down_url);
let save_path_file = `${save_path}/${fileName}` + suffix(data.type)
fileName = fileName + "_" + getCurrentDateTimeFormatted() + suffix(data.type)
let save_path_file = `${save_path}/${fileName}`
if (process.platform === 'win32') {
save_path_file = `${save_path}\\${fileName}` + suffix(data.type)
save_path_file = `${save_path}\\${fileName}`
}
if (fs.existsSync(save_path_file)) {
return {fullFileName: save_path_file, totalLen: ""}
let headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
}
// 开始下载
return downloadFile(
down_url,
data.decode_key,
save_path_file,
(res) => {
win?.webContents.send('on_down_file_schedule', {schedule: floor(res * 100)})
return new Promise((resolve, reject) => {
if (down_url.includes("douyin")) {
headers['Referer'] = down_url
}
).catch(err => {
// console.log("err:", err)
return false
})
aria2RpcClient.addUri([down_url], save_path, fileName, headers).then((response) => {
let currentGid = response.result // 保存当前下载的 gid
let progressIntervalId = null
// // 开始定时查询下载进度
progressIntervalId = setInterval(() => {
aria2RpcClient.tellStatus(currentGid).then((status) => {
if (status.result.status !== "complete") {
const progress = aria2RpcClient.calculateDownloadProgress(status.result.bitfield);
win?.webContents.send('on_down_file_schedule', {schedule: `已下载${progress}%`})
} else {
clearInterval(progressIntervalId);
if (data.decode_key) {
win?.webContents.send('on_down_file_schedule', {schedule: `开始解密`})
decodeWxFile(save_path_file, data.decode_key, save_path_file.replace(".mp4", "_wx.mp4")).then((res) => {
fs.unlink(save_path_file, (err) => {
})
resolve(res);
}).catch((error) => {
console.log("err:", error)
resolve(false);
});
} else {
resolve({
fullFileName: save_path_file,
});
}
}
}).catch((error) => {
console.error(error);
clearInterval(progressIntervalId);
resolve(false);
});
}, 1000);
}).catch((error) => {
console.log("err:", error)
resolve(false);
});
});
});
ipcMain.handle('invoke_resources_preview', async (event, {url}) => {
@@ -106,7 +151,8 @@ export default function initIPC() {
})
ipcMain.handle('invoke_open_default_browser', (event, {url}) => {
shell.openExternal(url).then(r => {})
shell.openExternal(url).then(r => {
})
})
ipcMain.handle('invoke_open_file_dir', (event, {save_path}) => {
@@ -114,7 +160,7 @@ export default function initIPC() {
})
ipcMain.handle('invoke_file_del', (event, {url_sign}) => {
if (url_sign === "all"){
if (url_sign === "all") {
global.videoList = {}
return
}
@@ -125,8 +171,8 @@ export default function initIPC() {
})
ipcMain.handle('invoke_window_restart', (event) => {
app.relaunch()
app.exit()
app.relaunch()
app.exit()
})
}

View File

@@ -1,8 +1,7 @@
import fs from 'fs'
import log from 'electron-log'
import CONFIG from './const'
import {closeProxy, setProxy} from './setProxy'
import {app} from "electron"
import {setProxy} from './setProxy'
import * as urlTool from "url"
import {toSize} from "./utils"
// @ts-ignore
@@ -23,6 +22,8 @@ if (process.platform === 'win32') {
const resObject = {
url: "",
url_sign: "",
cover_url: "",
file_format: "",
platform: "",
size: "",
type: "video/mp4",
@@ -71,12 +72,12 @@ export async function startServer({win, upstreamProxy, setProxyErrorCallback = f
res.string = 'ok'
res.statusCode = 200
try {
if (!req.json?.description || req.json?.media?.length <= 0) {
if (req.json?.media?.length <= 0) {
return
}
const media = req.json?.media[0]
const url_sign: string = hexMD5(media.url)
if (global.videoList.hasOwnProperty(url_sign) === true) {
if (!media?.decodeKey || global.videoList.hasOwnProperty(url_sign) === true) {
return
}
const urlInfo = urlTool.parse(media.url, true)
@@ -84,11 +85,13 @@ export async function startServer({win, upstreamProxy, setProxyErrorCallback = f
win.webContents.send('on_get_queue', Object.assign({}, resObject, {
url_sign: url_sign,
url: media.url + media.urlToken,
cover_url: media.coverUrl,
file_format: media.spec.map((res)=> res.fileFormat).join('#'),
platform: urlInfo.hostname,
size: media?.fileSize ? toSize(media.fileSize) : 0,
size: toSize(media.fileSize),
type: "video/mp4",
type_str: 'video',
decode_key: media?.decodeKey ? media?.decodeKey : '',
decode_key: media.decodeKey,
description: req.json.description,
}))
} catch (e) {
@@ -114,6 +117,7 @@ export async function startServer({win, upstreamProxy, setProxyErrorCallback = f
proxy.intercept(
{
phase: 'response',
hostname: 'res.wx.qq.com',
as: 'string',
},
async (req, res) => {
@@ -121,14 +125,6 @@ export async function startServer({win, upstreamProxy, setProxyErrorCallback = f
res.string = res.string.replaceAll('.js"', '.js?v=' + vv + '"');
}
if (req.url.includes("web/web-finder/res/js/virtual_svg-icons-register.publish")) {
// console.log(res.string.match(/return\s*\{\s*width:([\s\S]*?)scalingInfo:([\s\S]*?)\}/))
// res.string = res.string.replace(
// /return\s*{\s*width:(.*?)scalingInfo:(.*?)\s*}/,
// `var mediaInfo = {width:$1scalingInfo:$2};
// console.log("mediaInfo", mediaInfo);
// console.log("this.objectDesc", this.objectDesc);
// return mediaInfo;`
// )
res.string = res.string.replace(/get\s*media\s*\(\)\s*\{/, `
get media(){
if(this.objectDesc){
@@ -231,7 +227,6 @@ export async function startServer({win, upstreamProxy, setProxyErrorCallback = f
type_str: 'm3u8',
}))
break
}
} catch (e) {
log.log(e.toString())
@@ -242,14 +237,4 @@ export async function startServer({win, upstreamProxy, setProxyErrorCallback = f
log.log("--------------proxy catch err--------------", e)
}
})
}
app.on('before-quit', async e => {
e.preventDefault()
try {
await closeProxy()
log.log("--------------closeProxy success--------------")
} catch (error) {
}
app.exit()
})
}

View File

@@ -2,6 +2,7 @@ import {exec} from 'child_process'
// @ts-ignore
import regedit from 'regedit'
import CONFIG from './const'
import {dialog} from "electron";
regedit.setExternalVBSLocation(CONFIG.REGEDIT_VBS_PATH)
@@ -34,6 +35,12 @@ export async function setProxy(host, port) {
});
}),
);
} else if (process.platform === 'linux') {
dialog.showMessageBoxSync({
type: "info",
message: `请手动设置系统代理`,
});
return new Promise((resolve, reject) => {})
} else {
const valuesToPut = {
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings': {
@@ -81,6 +88,11 @@ export async function closeProxy() {
});
}),
);
} else if (process.platform === 'linux') {
dialog.showMessageBoxSync({
type: "info",
message: `请手动取消系统代理`,
});
} else {
const valuesToPut = {
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings': {
@@ -125,4 +137,4 @@ function getMacAvailableNetworks() {
}
})
})
}
}

View File

@@ -144,4 +144,17 @@ function suffix(type: string) {
return ""
}
export {downloadFile, toSize, decodeWxFile, suffix}
function getCurrentDateTimeFormatted() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始所以要加1
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `${year}${month}${day}${hours}${minutes}${seconds}`;
}
export {downloadFile, toSize, decodeWxFile, suffix, getCurrentDateTimeFormatted}

View File

@@ -0,0 +1,25 @@
#允许rpc
enable-rpc=true
#允许非外部访问
rpc-listen-all=true
#最大同时下载数(任务数), 路由建议值: 3
max-concurrent-downloads=3
#断点续传
continue=true
#同服务器连接数
max-connection-per-server=10
#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要
min-split-size=10M
#单文件最大线程数, 路由建议值: 5
split=10
#下载速度限制
max-overall-download-limit=0
#单文件速度限制
max-download-limit=0
#上传速度限制
max-overall-upload-limit=0
#单文件速度限制
max-upload-limit=0
check-certificate=false

Binary file not shown.

Binary file not shown.

View File

View File

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 199 KiB

View File

@@ -0,0 +1,25 @@
#允许rpc
enable-rpc=true
#允许非外部访问
rpc-listen-all=true
#最大同时下载数(任务数), 路由建议值: 3
max-concurrent-downloads=3
#断点续传
continue=true
#同服务器连接数
max-connection-per-server=10
#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要
min-split-size=10M
#单文件最大线程数, 路由建议值: 5
split=10
#下载速度限制
max-overall-download-limit=0
#单文件速度限制
max-download-limit=0
#上传速度限制
max-overall-upload-limit=0
#单文件速度限制
max-upload-limit=0
check-certificate=false

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,126 +0,0 @@
LICENSE ISSUES
==============
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts. Actually both licenses are BSD-style
Open Source licenses. In case of any license issues related to OpenSSL
please contact openssl-core@openssl.org.
OpenSSL License
---------------
/* ====================================================================
* Copyright (c) 1998-2016 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED 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 OpenSSL PROJECT OR
* ITS 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.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
Original SSLeay License
-----------------------
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/

View File

@@ -1,59 +0,0 @@
=============================================================================
OpenSSL v1.0.2q Precompiled Binaries for Win32
-----------------------------------------------------------------------------
*** Release Information ***
Release Date: Nov 22, 2018
Author: Frederik A. Winkelsdorf (opendec.wordpress.com)
for the Indy Project (www.indyproject.org)
Requirements: Indy 10.5.5+ (SVN Version or Delphi 2009 and newer)
Dependencies: The libraries have no noteworthy dependencies
Installation: Copy both DLL files into your application directory
Supported OS: Windows 2000 up to Windows 10
-----------------------------------------------------------------------------
*** Legal Disclaimer ***
THIS SOFTWARE IS PROVIDED BY ITS AUTHOR AND THE INDY PROJECT "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 REGENTS 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.
OpenSSL license terms are provided in the file "OpenSSL License.txt".
PLEASE CHECK IF YOU NEED TO COMPLY WITH EXPORT RESTRICTIONS FOR CRYPTOGRAPHIC
SOFTWARE AND/OR PATENTS.
-----------------------------------------------------------------------------
*** Build Information Win32 ***
Built with: Microsoft Visual C++ 2008 Express Edition
The Netwide Assembler (NASM) v2.11.08 Win32
Strawberry Perl v5.22.0.1 Win32 Portable
Windows PowerShell
FinalBuilder 7
Commands: perl configure VC-WIN32
ms\do_nasm
adjusted ms\ntdll.mak (replaced "/MD" with "/MT")
adjusted ms\version32.rc (Indy Information inserted)
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak test
editbin.exe /rebase:base=0x11000000 libeay32.dll
editbin.exe /rebase:base=0x12000000 ssleay32.dll
=============================================================================

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,25 @@
#允许rpc
enable-rpc=true
#允许非外部访问
rpc-listen-all=true
#最大同时下载数(任务数), 路由建议值: 3
max-concurrent-downloads=3
#断点续传
continue=true
#同服务器连接数
max-connection-per-server=10
#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要
min-split-size=10M
#单文件最大线程数, 路由建议值: 5
split=10
#下载速度限制
max-overall-download-limit=0
#单文件速度限制
max-download-limit=0
#上传速度限制
max-overall-upload-limit=0
#单文件速度限制
max-upload-limit=0
check-certificate=false

Binary file not shown.

239
electron/res/win/openssl/CA.pl Executable file
View File

@@ -0,0 +1,239 @@
#!/usr/bin/env perl
# Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#
# Wrapper around the ca to make it easier to use
#
# WARNING: do not edit!
# Generated by makefile from apps\CA.pl.in
use strict;
use warnings;
my $verbose = 1;
my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify");
my $openssl = $ENV{'OPENSSL'} // "openssl";
$ENV{'OPENSSL'} = $openssl;
my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // "";
# Command invocations.
my $REQ = "$openssl req $OPENSSL_CONFIG";
my $CA = "$openssl ca $OPENSSL_CONFIG";
my $VERIFY = "$openssl verify";
my $X509 = "$openssl x509";
my $PKCS12 = "$openssl pkcs12";
# Default values for various configuration settings.
my $CATOP = "./demoCA";
my $CAKEY = "cakey.pem";
my $CAREQ = "careq.pem";
my $CACERT = "cacert.pem";
my $CACRL = "crl.pem";
my $DAYS = "-days 365";
my $CADAYS = "-days 1095"; # 3 years
my $EXTENSIONS = "-extensions v3_ca";
my $POLICY = "-policy policy_anything";
my $NEWKEY = "newkey.pem";
my $NEWREQ = "newreq.pem";
my $NEWCERT = "newcert.pem";
my $NEWP12 = "newcert.p12";
# Commandline parsing
my %EXTRA;
my $WHAT = shift @ARGV || "";
@ARGV = parse_extra(@ARGV);
my $RET = 0;
# Split out "-extra-CMD value", and return new |@ARGV|. Fill in
# |EXTRA{CMD}| with list of values.
sub parse_extra
{
foreach ( @OPENSSL_CMDS ) {
$EXTRA{$_} = '';
}
my @result;
while ( scalar(@_) > 0 ) {
my $arg = shift;
if ( $arg !~ m/-extra-([a-z0-9]+)/ ) {
push @result, $arg;
next;
}
$arg =~ s/-extra-//;
die("Unknown \"-${arg}-extra\" option, exiting")
unless scalar grep { $arg eq $_ } @OPENSSL_CMDS;
$EXTRA{$arg} .= " " . shift;
}
return @result;
}
# See if reason for a CRL entry is valid; exit if not.
sub crl_reason_ok
{
my $r = shift;
if ($r eq 'unspecified' || $r eq 'keyCompromise'
|| $r eq 'CACompromise' || $r eq 'affiliationChanged'
|| $r eq 'superseded' || $r eq 'cessationOfOperation'
|| $r eq 'certificateHold' || $r eq 'removeFromCRL') {
return 1;
}
print STDERR "Invalid CRL reason; must be one of:\n";
print STDERR " unspecified, keyCompromise, CACompromise,\n";
print STDERR " affiliationChanged, superseded, cessationOfOperation\n";
print STDERR " certificateHold, removeFromCRL";
exit 1;
}
# Copy a PEM-format file; return like exit status (zero means ok)
sub copy_pemfile
{
my ($infile, $outfile, $bound) = @_;
my $found = 0;
open IN, $infile || die "Cannot open $infile, $!";
open OUT, ">$outfile" || die "Cannot write to $outfile, $!";
while (<IN>) {
$found = 1 if /^-----BEGIN.*$bound/;
print OUT $_ if $found;
$found = 2, last if /^-----END.*$bound/;
}
close IN;
close OUT;
return $found == 2 ? 0 : 1;
}
# Wrapper around system; useful for debugging. Returns just the exit status
sub run
{
my $cmd = shift;
print "====\n$cmd\n" if $verbose;
my $status = system($cmd);
print "==> $status\n====\n" if $verbose;
return $status >> 8;
}
if ( $WHAT =~ /^(-\?|-h|-help)$/ ) {
print STDERR <<EOF;
Usage:
CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter]
CA.pl -pkcs12 [certname]
CA.pl -verify certfile ...
CA.pl -revoke certfile [reason]
EOF
exit 0;
}
if ($WHAT eq '-newcert' ) {
# create a certificate
$RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS"
. " $EXTRA{req}");
print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT eq '-precert' ) {
# create a pre-certificate
$RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS"
. " $EXTRA{req}");
print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) {
# create a certificate request
$RET = run("$REQ -new $1 -keyout $NEWKEY -out $NEWREQ $DAYS $EXTRA{req}");
print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT eq '-newca' ) {
# create the directory hierarchy
my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl",
"${CATOP}/newcerts", "${CATOP}/private" );
die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed,"
if -f "${CATOP}/index.txt";
die "${CATOP}/serial exists.\nRemove old sub-tree to proceed,"
if -f "${CATOP}/serial";
foreach my $d ( @dirs ) {
if ( -d $d ) {
warn "Directory $d exists" if -d $d;
} else {
mkdir $d or die "Can't mkdir $d, $!";
}
}
open OUT, ">${CATOP}/index.txt";
close OUT;
open OUT, ">${CATOP}/crlnumber";
print OUT "01\n";
close OUT;
# ask user for existing CA certificate
print "CA certificate filename (or enter to create)\n";
my $FILE;
$FILE = "" unless defined($FILE = <STDIN>);
$FILE =~ s{\R$}{};
if ($FILE ne "") {
copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE");
copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE");
} else {
print "Making CA certificate ...\n";
$RET = run("$REQ -new -keyout ${CATOP}/private/$CAKEY"
. " -out ${CATOP}/$CAREQ $EXTRA{req}");
$RET = run("$CA -create_serial"
. " -out ${CATOP}/$CACERT $CADAYS -batch"
. " -keyfile ${CATOP}/private/$CAKEY -selfsign"
. " $EXTENSIONS"
. " -infiles ${CATOP}/$CAREQ $EXTRA{ca}") if $RET == 0;
print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0;
}
} elsif ($WHAT eq '-pkcs12' ) {
my $cname = $ARGV[0];
$cname = "My Certificate" unless defined $cname;
$RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY"
. " -certfile ${CATOP}/$CACERT -out $NEWP12"
. " -export -name \"$cname\" $EXTRA{pkcs12}");
print "PKCS #12 file is in $NEWP12\n" if $RET == 0;
} elsif ($WHAT eq '-xsign' ) {
$RET = run("$CA $POLICY -infiles $NEWREQ $EXTRA{ca}");
} elsif ($WHAT eq '-sign' ) {
$RET = run("$CA $POLICY -out $NEWCERT"
. " -infiles $NEWREQ $EXTRA{ca}");
print "Signed certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-signCA' ) {
$RET = run("$CA $POLICY -out $NEWCERT"
. " $EXTENSIONS -infiles $NEWREQ $EXTRA{ca}");
print "Signed CA certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-signcert' ) {
$RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ"
. " -out tmp.pem $EXTRA{x509}");
$RET = run("$CA $POLICY -out $NEWCERT"
. "-infiles tmp.pem $EXTRA{ca}") if $RET == 0;
print "Signed certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-verify' ) {
my @files = @ARGV ? @ARGV : ( $NEWCERT );
foreach my $file (@files) {
# -CAfile quoted for VMS, since the C RTL downcases all unquoted
# arguments to C programs
my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file $EXTRA{verify}");
$RET = $status if $status != 0;
}
} elsif ($WHAT eq '-crl' ) {
$RET = run("$CA -gencrl -out ${CATOP}/crl/$CACRL $EXTRA{ca}");
print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0;
} elsif ($WHAT eq '-revoke' ) {
my $cname = $ARGV[0];
if (!defined $cname) {
print "Certificate filename is required; reason optional.\n";
exit 1;
}
my $reason = $ARGV[1];
$reason = " -crl_reason $reason"
if defined $reason && crl_reason_ok($reason);
$RET = run("$CA -revoke \"$cname\"" . $reason . $EXTRA{ca});
} else {
print STDERR "Unknown arg \"$WHAT\"\n";
print STDERR "Use -help for help.\n";
exit 1;
}
exit $RET;

BIN
electron/res/win/openssl/capi.dll Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

218
electron/res/win/openssl/progs.pl Executable file
View File

@@ -0,0 +1,218 @@
#! /usr/bin/env perl
# Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
# Generate progs.h file by looking for command mains in list of C files
# passed on the command line.
use strict;
use warnings;
use lib '.';
use configdata qw/@disablables %unified_info/;
my $opt = shift @ARGV;
die "Unrecognised option, must be -C or -H\n"
unless ($opt eq '-H' || $opt eq '-C');
my %commands = ();
my $cmdre = qr/^\s*int\s+([a-z_][a-z0-9_]*)_main\(\s*int\s+argc\s*,/;
my $apps_openssl = shift @ARGV;
my $YEAR = [gmtime($ENV{SOURCE_DATE_EPOCH} || time())]->[5] + 1900;
# because the program apps/openssl has object files as sources, and
# they then have the corresponding C files as source, we need to chain
# the lookups in %unified_info
my @openssl_source =
map { @{$unified_info{sources}->{$_}} }
grep { /\.o$/
&& !$unified_info{attributes}->{sources}->{$apps_openssl}->{$_}->{nocheck} }
@{$unified_info{sources}->{$apps_openssl}};
foreach my $filename (@openssl_source) {
open F, $filename or die "Couldn't open $filename: $!\n";
foreach ( grep /$cmdre/, <F> ) {
my @foo = /$cmdre/;
$commands{$1} = 1;
}
close F;
}
@ARGV = sort keys %commands;
if ($opt eq '-H') {
print <<"EOF";
/*
* WARNING: do not edit!
* Generated by apps/progs.pl
*
* Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "function.h"
EOF
foreach (@ARGV) {
printf "extern int %s_main(int argc, char *argv[]);\n", $_;
}
print "\n";
foreach (@ARGV) {
printf "extern const OPTIONS %s_options[];\n", $_;
}
print "\n";
print "extern FUNCTION functions[];\n";
}
if ($opt eq '-C') {
print <<"EOF";
/*
* WARNING: do not edit!
* Generated by apps/progs.pl
*
* Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "progs.h"
EOF
my %cmd_disabler = (
ciphers => "sock",
genrsa => "rsa",
gendsa => "dsa",
dsaparam => "dsa",
gendh => "dh",
dhparam => "dh",
ecparam => "ec",
);
my %cmd_deprecated = (
# The format of this table is:
# [0] = alternative command to use instead
# [1] = deprecented in this version
# [2] = preprocessor conditional for excluding irrespective of deprecation
# rsa => [ "pkey", "3_0", "rsa" ],
# genrsa => [ "genpkey", "3_0", "rsa" ],
rsautl => [ "pkeyutl", "3_0", "rsa" ],
# dhparam => [ "pkeyparam", "3_0", "dh" ],
# dsaparam => [ "pkeyparam", "3_0", "dsa" ],
# dsa => [ "pkey", "3_0", "dsa" ],
# gendsa => [ "genpkey", "3_0", "dsa" ],
# ec => [ "pkey", "3_0", "ec" ],
# ecparam => [ "pkeyparam", "3_0", "ec" ],
);
print "FUNCTION functions[] = {\n";
foreach my $cmd ( @ARGV ) {
my $str =
" {FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options, NULL, NULL},\n";
if ($cmd =~ /^s_/) {
print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n";
} elsif (my $deprecated = $cmd_deprecated{$cmd}) {
my @dep = @{$deprecated};
my $daltprg = $dep[0];
my $dver = $dep[1];
my $dsys = $dep[2];
print "#if !defined(OPENSSL_NO_DEPRECATED_" . $dver . ")";
if ($dsys) {
print " && !defined(OPENSSL_NO_" . uc($dsys) . ")";
}
$dver =~ s/_/./g;
my $dalt = "\"" . $daltprg . "\", \"" . $dver . "\"";
$str =~ s/NULL, NULL/$dalt/;
print "\n${str}#endif\n";
} elsif (grep { $cmd eq $_ } @disablables) {
print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
} elsif (my $disabler = $cmd_disabler{$cmd}) {
print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
} else {
print $str;
}
}
my %md_disabler = (
blake2b512 => "blake2",
blake2s256 => "blake2",
);
foreach my $cmd (
"md2", "md4", "md5",
"sha1", "sha224", "sha256", "sha384",
"sha512", "sha512-224", "sha512-256",
"sha3-224", "sha3-256", "sha3-384", "sha3-512",
"shake128", "shake256",
"mdc2", "rmd160", "blake2b512", "blake2s256",
"sm3"
) {
my $str = " {FT_md, \"$cmd\", dgst_main, NULL, NULL},\n";
if (grep { $cmd eq $_ } @disablables) {
print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
} elsif (my $disabler = $md_disabler{$cmd}) {
print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
} else {
print $str;
}
}
my %cipher_disabler = (
des3 => "des",
desx => "des",
cast5 => "cast",
);
foreach my $cmd (
"aes-128-cbc", "aes-128-ecb",
"aes-192-cbc", "aes-192-ecb",
"aes-256-cbc", "aes-256-ecb",
"aria-128-cbc", "aria-128-cfb",
"aria-128-ctr", "aria-128-ecb", "aria-128-ofb",
"aria-128-cfb1", "aria-128-cfb8",
"aria-192-cbc", "aria-192-cfb",
"aria-192-ctr", "aria-192-ecb", "aria-192-ofb",
"aria-192-cfb1", "aria-192-cfb8",
"aria-256-cbc", "aria-256-cfb",
"aria-256-ctr", "aria-256-ecb", "aria-256-ofb",
"aria-256-cfb1", "aria-256-cfb8",
"camellia-128-cbc", "camellia-128-ecb",
"camellia-192-cbc", "camellia-192-ecb",
"camellia-256-cbc", "camellia-256-ecb",
"base64", "zlib", "brotli", "zstd",
"des", "des3", "desx", "idea", "seed", "rc4", "rc4-40",
"rc2", "bf", "cast", "rc5",
"des-ecb", "des-ede", "des-ede3",
"des-cbc", "des-ede-cbc","des-ede3-cbc",
"des-cfb", "des-ede-cfb","des-ede3-cfb",
"des-ofb", "des-ede-ofb","des-ede3-ofb",
"idea-cbc","idea-ecb", "idea-cfb", "idea-ofb",
"seed-cbc","seed-ecb", "seed-cfb", "seed-ofb",
"rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc",
"bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb",
"cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb",
"cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb",
"sm4-cbc", "sm4-ecb", "sm4-cfb", "sm4-ofb", "sm4-ctr"
) {
my $str = " {FT_cipher, \"$cmd\", enc_main, enc_options, NULL},\n";
(my $algo = $cmd) =~ s/-.*//g;
if (grep { $algo eq $_ } @disablables) {
print "#ifndef OPENSSL_NO_" . uc($algo) . "\n${str}#endif\n";
} elsif (my $disabler = $cipher_disabler{$algo}) {
print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
} else {
print $str;
}
}
print " {0, NULL, NULL, NULL, NULL}\n};\n";
}

200
electron/res/win/openssl/tsget.pl Executable file
View File

@@ -0,0 +1,200 @@
#!/usr/bin/env perl
# Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved.
# Copyright (c) 2002 The OpenTSA Project. All rights reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
use strict;
use IO::Handle;
use Getopt::Std;
use File::Basename;
use WWW::Curl::Easy;
use vars qw(%options);
# Callback for reading the body.
sub read_body {
my ($maxlength, $state) = @_;
my $return_data = "";
my $data_len = length ${$state->{data}};
if ($state->{bytes} < $data_len) {
$data_len = $data_len - $state->{bytes};
$data_len = $maxlength if $data_len > $maxlength;
$return_data = substr ${$state->{data}}, $state->{bytes}, $data_len;
$state->{bytes} += $data_len;
}
return $return_data;
}
# Callback for writing the body into a variable.
sub write_body {
my ($data, $pointer) = @_;
${$pointer} .= $data;
return length($data);
}
# Initialise a new Curl object.
sub create_curl {
my $url = shift;
# Create Curl object.
my $curl = WWW::Curl::Easy::new();
# Error-handling related options.
$curl->setopt(CURLOPT_VERBOSE, 1) if $options{d};
$curl->setopt(CURLOPT_FAILONERROR, 1);
$curl->setopt(CURLOPT_USERAGENT,
"OpenTSA tsget.pl/openssl-3.3.1");
# Options for POST method.
$curl->setopt(CURLOPT_UPLOAD, 1);
$curl->setopt(CURLOPT_CUSTOMREQUEST, "POST");
$curl->setopt(CURLOPT_HTTPHEADER,
["Content-Type: application/timestamp-query",
"Accept: application/timestamp-reply,application/timestamp-response"]);
$curl->setopt(CURLOPT_READFUNCTION, \&read_body);
$curl->setopt(CURLOPT_HEADERFUNCTION, sub { return length($_[0]); });
# Options for getting the result.
$curl->setopt(CURLOPT_WRITEFUNCTION, \&write_body);
# SSL related options.
$curl->setopt(CURLOPT_SSLKEYTYPE, "PEM");
$curl->setopt(CURLOPT_SSL_VERIFYPEER, 1); # Verify server's certificate.
$curl->setopt(CURLOPT_SSL_VERIFYHOST, 2); # Check server's CN.
$curl->setopt(CURLOPT_SSLKEY, $options{k}) if defined($options{k});
$curl->setopt(CURLOPT_SSLKEYPASSWD, $options{p}) if defined($options{p});
$curl->setopt(CURLOPT_SSLCERT, $options{c}) if defined($options{c});
$curl->setopt(CURLOPT_CAINFO, $options{C}) if defined($options{C});
$curl->setopt(CURLOPT_CAPATH, $options{P}) if defined($options{P});
$curl->setopt(CURLOPT_RANDOM_FILE, $options{r}) if defined($options{r});
$curl->setopt(CURLOPT_EGDSOCKET, $options{g}) if defined($options{g});
# Setting destination.
$curl->setopt(CURLOPT_URL, $url);
return $curl;
}
# Send a request and returns the body back.
sub get_timestamp {
my $curl = shift;
my $body = shift;
my $ts_body;
local $::error_buf;
# Error-handling related options.
$curl->setopt(CURLOPT_ERRORBUFFER, "::error_buf");
# Options for POST method.
$curl->setopt(CURLOPT_INFILE, {data => $body, bytes => 0});
$curl->setopt(CURLOPT_INFILESIZE, length(${$body}));
# Options for getting the result.
$curl->setopt(CURLOPT_FILE, \$ts_body);
# Send the request...
my $error_code = $curl->perform();
my $error_string;
if ($error_code != 0) {
my $http_code = $curl->getinfo(CURLINFO_HTTP_CODE);
$error_string = "could not get timestamp";
$error_string .= ", http code: $http_code" unless $http_code == 0;
$error_string .= ", curl code: $error_code";
$error_string .= " ($::error_buf)" if defined($::error_buf);
} else {
my $ct = $curl->getinfo(CURLINFO_CONTENT_TYPE);
if (lc($ct) ne "application/timestamp-reply"
&& lc($ct) ne "application/timestamp-response") {
$error_string = "unexpected content type returned: $ct";
}
}
return ($ts_body, $error_string);
}
# Print usage information and exists.
sub usage {
print STDERR "usage: $0 -h <server_url> [-e <extension>] [-o <output>] ";
print STDERR "[-v] [-d] [-k <private_key.pem>] [-p <key_password>] ";
print STDERR "[-c <client_cert.pem>] [-C <CA_certs.pem>] [-P <CA_path>] ";
print STDERR "[-r <file:file...>] [-g <EGD_socket>] [<request>]...\n";
exit 1;
}
# ----------------------------------------------------------------------
# Main program
# ----------------------------------------------------------------------
# Getting command-line options (default comes from TSGET environment variable).
my $getopt_arg = "h:e:o:vdk:p:c:C:P:r:g:";
if (exists $ENV{TSGET}) {
my @old_argv = @ARGV;
@ARGV = split /\s+/, $ENV{TSGET};
getopts($getopt_arg, \%options) or usage;
@ARGV = @old_argv;
}
getopts($getopt_arg, \%options) or usage;
# Checking argument consistency.
if (!exists($options{h}) || (@ARGV == 0 && !exists($options{o}))
|| (@ARGV > 1 && exists($options{o}))) {
print STDERR "Inconsistent command line options.\n";
usage;
}
# Setting defaults.
@ARGV = ("-") unless @ARGV != 0;
$options{e} = ".tsr" unless defined($options{e});
# Processing requests.
my $curl = create_curl $options{h};
undef $/; # For reading whole files.
REQUEST: foreach (@ARGV) {
my $input = $_;
my ($base, $path) = fileparse($input, '\.[^.]*');
my $output_base = $base . $options{e};
my $output = defined($options{o}) ? $options{o} : $path . $output_base;
STDERR->printflush("$input: ") if $options{v};
# Read request.
my $body;
if ($input eq "-") {
# Read the request from STDIN;
$body = <STDIN>;
} else {
# Read the request from file.
open INPUT, "<" . $input
or warn("$input: could not open input file: $!\n"), next REQUEST;
$body = <INPUT>;
close INPUT
or warn("$input: could not close input file: $!\n"), next REQUEST;
}
# Send request.
STDERR->printflush("sending request") if $options{v};
my ($ts_body, $error) = get_timestamp $curl, \$body;
if (defined($error)) {
die "$input: fatal error: $error\n";
}
STDERR->printflush(", reply received") if $options{v};
# Write response.
if ($output eq "-") {
# Write to STDOUT.
print $ts_body;
} else {
# Write to file.
open OUTPUT, ">", $output
or warn("$output: could not open output file: $!\n"), next REQUEST;
print OUTPUT $ts_body;
close OUTPUT
or warn("$output: could not close output file: $!\n"), next REQUEST;
}
STDERR->printflush(", $output written.\n") if $options{v};
}
$curl->cleanup();

View File

BIN
electron/res/win/w_c.exe Normal file

Binary file not shown.

View File

@@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<meta charset="UTF-8"/>
<link rel="icon" href="/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
<title>爱享素材下载器</title>
</head>
<body>

View File

@@ -1,9 +1,13 @@
{
"name": "res-downloader",
"version": "2.0.0",
"version": "2.1.1",
"main": "dist-electron/main/index.js",
"description": "res-downloader(爱享素材下载器)支持视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐下载等",
"author": "putyy@qq.com",
"description": "res-downloader(爱享素材下载器)支持视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐、qq短视频等",
"homepage": "https://github.com/putyy/res-downloader",
"author": {
"name": "putyy",
"email": "putyy@qq.com"
},
"license": "MIT",
"private": true,
"keywords": [
@@ -19,8 +23,8 @@
}
},
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build && electron-builder",
"dev": "node script/hoxy.ts && vite",
"build": "node script/hoxy.ts && vue-tsc --noEmit && vite build && electron-builder",
"preview": "vite preview"
},
"devDependencies": {
@@ -50,7 +54,7 @@
"vite-plugin-electron-renderer": "^0.14.5",
"vue": "^3.3.4",
"vue-router": "^4.2.4",
"vue-tsc": "^1.8.8"
"vue-tsc": "^2.0.29"
},
"dependencies": {
"axios": "^1.5.0",

7
script/hoxy.ts Normal file
View File

@@ -0,0 +1,7 @@
const fs = require('fs');
const path = require('path');
const currentDir = process.cwd();
// 移动文件
fs.copyFile(currentDir + '/override/hoxy/lib/cycle.js', currentDir + '/node_modules/hoxy/lib/cycle.js', fs.constants.COPYFILE_FICLONE, (err) => {
});

View File

@@ -12,7 +12,10 @@ el-container
Sidebar
el-container
el-main
router-view
router-view(v-slot="{ Component, route }")
keep-alive(v-if="route.meta.keepAlive")
component(:is="Component")
component(v-else :is="Component")
el-footer
Footer
</template>

View File

@@ -13,16 +13,19 @@ const routes = [
{
path: '/index',
name: 'Index',
meta: {keepAlive: true},
component: () => import('./views/Index.vue'),
},
{
path: '/about',
name: 'about',
meta: {keepAlive: true},
component: () => import('./views/About.vue'),
},
{
path: '/setting',
name: 'Setting',
meta: {keepAlive: true},
component: () => import('./views/Setting.vue'),
},
]

View File

@@ -54,7 +54,7 @@ onMounted(() => {
})
ipcRenderer.on('on_down_file_schedule', (res: any, data: any) => {
loading.value && loading.value.setText(`已下载 ${data.schedule}%`)
loading.value && loading.value.setText(`${data.schedule}%`)
})
ipcRenderer.invoke('invoke_app_is_init').then((isInit: boolean) => {
@@ -119,22 +119,12 @@ const handleBatchDown = async () => {
text: '下载中',
background: 'rgba(0, 0, 0, 0.7)',
})
const quality = localStorageCache.get("quality") ? localStorageCache.get("quality") : -1
for (const item of multipleSelection.value) {
let result = await ipcRenderer.invoke('invoke_file_exists', {
save_path: save_dir,
url: item.url,
})
if (result.is_file) {
item.progress_bar = "100%"
item.save_path = result.fileName
continue
}
let downRes = await ipcRenderer.invoke('invoke_down_file', {
data: Object.assign({}, item),
save_path: save_dir,
quality: quality,
})
if (downRes !== false) {
@@ -148,9 +138,7 @@ const handleBatchDown = async () => {
const handleDown = async (index: number, row: any) => {
let save_dir = localStorageCache.get("save_dir")
const save_dir = localStorageCache.get("save_dir")
if (!save_dir) {
ElMessage({
message: '请设置保存目录',
@@ -165,26 +153,11 @@ const handleDown = async (index: number, row: any) => {
background: 'rgba(0, 0, 0, 0.7)',
})
let result = await ipcRenderer.invoke('invoke_file_exists', {
save_path: save_dir,
url: row.url,
description: row.description
})
if (result.is_file) {
tableData.value[index].progress_bar = "100%"
tableData.value[index].save_path = result.fileName
ElMessage({
message: "文件已存在(" + result.fileName + ")",
type: 'warning',
})
loading.value.close()
localStorageCache.set("res-table-data", tableData.value, -1)
return
}
const quality = localStorageCache.get("quality") ? localStorageCache.get("quality") : -1
ipcRenderer.invoke('invoke_down_file', {
data: Object.assign({}, tableData.value[index]),
save_path: save_dir
save_path: save_dir,
quality: quality,
}).then((res) => {
if (res !== false) {
tableData.value[index].progress_bar = "100%"
@@ -317,10 +290,10 @@ el-container.container
el-main
el-table(ref="multipleTableRef" @selection-change="handleSelectionChange" :data="tableData" max-height="100%" stripe)
el-table-column(type="selection")
el-table-column(label="预览" show-overflow-tooltip width="300px")
el-table-column(label="预览" show-overflow-tooltip width="150px")
template(#default="scope")
div.show_res
video.video(v-if="scope.row.type_str === 'video'" :src="scope.row.url" controls preload="none") 您的浏览器不支持 video 标签
video.video(v-if="scope.row.type_str === 'video'" :src="scope.row.url" controls preload="none")
img.img(v-if="scope.row.type_str === 'image'" :src="scope.row.url" crossorigin="anonymous")
audio.audio(v-if="scope.row.type_str === 'audio'" controls preload="none")
source(:src="scope.row.url" :type="scope.row.type")
@@ -334,7 +307,7 @@ el-container.container
template(#default="scope")
div.actions
template(v-if="scope.row.type_str !== 'm3u8'" )
el-button(v-if="!scope.row.save_path" link type="primary" @click="handleDown(scope.$index, scope.row)") {{scope.row.decode_key || scope.row.decryptor_array ? "解密下载(视频号)" : "下载"}}
el-button(link type="primary" @click="handleDown(scope.$index, scope.row)") {{scope.row.decode_key || scope.row.decryptor_array ? "解密下载(视频号)" : "下载"}}
el-button(v-if="scope.row.decode_key || scope.row.decryptor_array" link type="primary" @click="decodeWxFile(scope.$index)") 视频解密(视频号)
el-button(link type="primary" @click="handlePreview(scope.$index, scope.row)") 窗口预览
el-button(link type="primary" @click="handleCopy(scope.row.url)") 复制链接
@@ -374,12 +347,13 @@ el-container.container
}
.show_res {
width: 100%;
height: auto;
.img {
max-height: 200px;
}
.video {
width: auto;
max-height: 200px;
}
}
.actions {

View File

@@ -7,9 +7,26 @@ import {ElMessage} from "element-plus"
const saveDir = ref("")
const upstream_proxy = ref("")
const upstream_proxy_old = ref("")
const quality = ref("-1")
const qualityOptions = ref([
{
value: '-1',
label: '默认(推荐)'
}, {
value: '0',
label: '高画质'
}, {
value: '1',
label: '中画质'
}, {
value: '2',
label: '低画质'
}
])
onMounted(() => {
saveDir.value = localStorageCache.get("save_dir") ? localStorageCache.get("save_dir") : ""
quality.value = localStorageCache.get("quality") ? localStorageCache.get("quality") : "-1"
upstream_proxy.value = localStorageCache.get("upstream_proxy") ? localStorageCache.get("upstream_proxy") : ""
upstream_proxy_old.value = upstream_proxy.value
})
@@ -25,22 +42,29 @@ const selectSaveDir = () => {
const onSetting = () => {
localStorageCache.set("save_dir", saveDir.value, -1)
localStorageCache.set("upstream_proxy", upstream_proxy.value, -1)
localStorageCache.set("quality", quality.value, -1)
if (upstream_proxy_old.value != upstream_proxy.value){
ipcRenderer.invoke('invoke_window_restart')
}
ElMessage({
message: "操作成功",
message: "保存成功",
type: 'success',
})
}
</script>
<template lang="pug">
el-form
el-form(style="max-width: 600px")
el-form-item(label="保存位置")
el-button(@click="selectSaveDir") {{saveDir ? saveDir : '选择'}}
el-form-item(label="代理服务")
el-input(v-model="upstream_proxy" placeholder="例如: http://127.0.0.1:7890 修改此项需重启本软件" )
el-link(@click="selectSaveDir") {{saveDir ? saveDir : '选择'}}
el-form-item(label="视频号画质")
el-select(v-model="quality" placeholder="请选择")
el-option( v-for="item in qualityOptions"
:key="item.value"
:label="item.label"
:value="item.value")
el-form-item(label="特殊代理")
el-input(v-model="upstream_proxy" placeholder="例如: http://127.0.0.1:7890 修改此项需重启本软件,如不清楚用途请勿设置。" )
el-form-item
el-button(type="primary" @click="onSetting") 保存
</template>