From 3faf8ce0e7b420dded87a6c7a8e2eb1d04158f8f Mon Sep 17 00:00:00 2001 From: Minemetero <156386015+Minemetero@users.noreply.github.com> Date: Tue, 14 May 2024 20:51:05 +0900 Subject: [PATCH 1/6] =?UTF-8?q?dev=20branch=E6=AD=A3=E5=BC=8F=E6=8E=A8?= =?UTF-8?q?=E5=87=BA=20(#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 补:更新 README.md * 再补:更新 README.md 艹,没补好 --------- Co-authored-by: Lingbo --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 700d0ef..3d57358 100644 --- a/README.md +++ b/README.md @@ -30,20 +30,27 @@ npm install ### 4. 运行 -在克隆的文件夹内运行: +在克隆的文件夹内运行以下命令 确保你有执行权限: ```shell chmod +x main.js updateHosts.js ipFetcher.js ``` - +然后运行主程序: ```shell ./main.js ``` +或者: +```shell +node main.js +``` + + 有 3 种可选的选项,详见[选项](#选项)。 - 如果写入失败,请尝试以管理员运行(Windows),或者以超级用户权限执行(`sudo`,Linux/Mac) - _(PS:测试的时候只测了 `Windows`,`Linux` 不保证完全可行)_ _(另一位开发只测试了llnux,其他的就交给大怨种了)_ +如果写入失败,请尝试以管理员运行(Windows),或者以超级用户权限执行(`sudo`,Linux/Mac) +_(PS:测试的时候只测了 `Windows`,`Linux` 不保证完全可行)_ +_(另一位开发只测试了Linux,其他的就交给大怨种了)_ ### 5. 完事! @@ -69,7 +76,7 @@ node main.js --noedit ### --diff -不修改文件,只输出更改了的内容(必须和 [`--noedit`](#noedit) 选项一同使用)。 +不修改文件,只输出更改了的内容(必须和 [`--noedit`](#--noedit) 选项一同使用)。 ```shell node main.js --noedit --diff @@ -77,11 +84,11 @@ node main.js --noedit --diff ## TODO -[ ] 完善域名列表 -[ ] 使其可以用于所有这样的网站 -[ ] 优化代码,增加可读性 -[ ] 简化步骤,试图让用户一键配置,跑完代码 -[ ] 对于Linux的支持 +- [ ] 完善域名列表 +- [ ] 使其可以用于所有这样的网站 +- [ ] 优化代码,增加可读性 +- [ ] 简化步骤,试图让用户一键配置,跑完代码 +- [ ] 对于Linux的支持 ## 开源说明 From 214ad8c03fe96276bbda0f4a398ad783f503460b Mon Sep 17 00:00:00 2001 From: Minemetero Date: Sun, 26 May 2024 20:30:23 +0900 Subject: [PATCH 2/6] 1.3.0 Add backup feature and README.md update --- LICENSE | 2 +- README.md | 19 +++- docs/README-dev.md | 85 +++++++++++++++ package.json | 5 +- restoreHosts.js | 38 +++++++ updateHosts.js | 260 ++++++++++++++------------------------------- 6 files changed, 225 insertions(+), 184 deletions(-) create mode 100644 docs/README-dev.md create mode 100644 restoreHosts.js diff --git a/LICENSE b/LICENSE index 5124aee..48da180 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 lingbopro +Copyright (c) 2024 lingbopro, and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3d57358..eb93f92 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ npm install 确保你有执行权限: ```shell +#似乎这只是Linux的专属指令 chmod +x main.js updateHosts.js ipFetcher.js ``` 然后运行主程序: @@ -46,14 +47,28 @@ chmod +x main.js updateHosts.js ipFetcher.js node main.js ``` - 有 3 种可选的选项,详见[选项](#选项)。 如果写入失败,请尝试以管理员运行(Windows),或者以超级用户权限执行(`sudo`,Linux/Mac) _(PS:测试的时候只测了 `Windows`,`Linux` 不保证完全可行)_ -_(另一位开发只测试了Linux,其他的就交给大怨种了)_ +_ (另一位开发只测试了Linux,其他的就交给大怨种了) _ ### 5. 完事! +#### 什么?你想改回你的Hosts文件? +~hahaha,你别想该回去了~ + +恢复hosts文件 + +要从备份中恢复原始的`hosts`文件,请按以下步骤操作: + +1. **运行恢复命令**:使用以下命令恢复您的`hosts`文件。 + + ```sh + npm run restore + ``` + +2. **完成**:程序将在原始`hosts`文件恢复完成后通知您。 + ## 选项 可以在运行时在命令中增加可选的选项(见下) diff --git a/docs/README-dev.md b/docs/README-dev.md new file mode 100644 index 0000000..0b257c4 --- /dev/null +++ b/docs/README-dev.md @@ -0,0 +1,85 @@ +# Easy GitHub Hosts - Development Guide + +This document provides a detailed guide for developers who wish to understand, modify, or contribute to the Easy GitHub Hosts project. + +## Table of Contents + +1. [Project Structure](#project-structure) +2. [Installation](#installation) +3. [Usage](#usage) +4. [Scripts](#scripts) +5. [Development Workflow](#development-workflow) +6. [Code Overview](#code-overview) + - [ipFetcher.js](#ipfetcherjs) + - [updateHosts.js](#updatehostsjs) + - [restoreHosts.js](#restorehostsjs) + - [main.js](#mainjs) +7. [Contributing](#contributing) +8. [License](#license) + +## Project Structure + +The project has the following structure: + +easy-github-hosts/ +├── .github/ +│ ├── bug_report.md +│ ├── feature_request.md +├── docs/ +│ ├── README.md +│ ├── README-dev.md +├── ipFetcher.js +├── main.js +├── package.json +├── restoreHosts.js +├── updateHosts.js + +- **.github/**: Contains the issue template files. + - **bug_report.md**: Yes! It for bug report issue. + - **feature_request.md**: Yes! It for feature request issue. +- **docs/**: Contains the documentation files. + - **README.md**: Provides general information and usage instructions. + - **README-dev.md**: This development guide. +- **ipFetcher.js**: Contains functions to fetch the IP addresses for GitHub-related domains. +- **main.js**: The main entry point for the program. +- **package.json**: Manages project dependencies and scripts. +- **restoreHosts.js**: Contains functions to restore the original `hosts` file. +- **updateHosts.js**: Contains functions to update the `hosts` file with new IP addresses. + +## Code Overview + +### ipFetcher.js + +This file contains the logic to fetch IP addresses for a list of GitHub-related domains using axios and cheerio: + +**getIP(host)**: Fetches the IP address for a given host. +**getIPs()**: Fetches IP addresses for all predefined GitHub-related domains. + + +### updateHosts.js +This file contains the logic to update the hosts file: + +**checkIPv4(IP)**: Checks if a string is a valid IPv4 address. +**parseHostsRecord(record)**: Parses a single record from the hosts file. +**getHostsRecords(content)**: Parses all records from the hosts file. +**getHostsRecordIndexByHost(records, host)**: Finds the index of a record by host. +**genHosts(records)**: Generates the content for the hosts file from records. +**createBackup(hostsPath)**: Creates a backup of the hosts file. +**updateHosts()**: Main function to update the hosts file. + +### restoreHosts.js +This file contains the logic to restore the original hosts file from a backup: + +**restoreHosts()**: Main function to restore the hosts file from a backup. + +### main.js +This file serves as the entry point for the program. It imports and runs the updateHosts function from updateHosts.js. + +## Contributing +Contributions are welcome! Please follow these guidelines: + +Fork the repository. +Create a new branch for your feature or bug fix. +Commit your changes with a descriptive message. +Push your branch to your fork. +Submit a pull request to the main repository **(dev branch)**. \ No newline at end of file diff --git a/package.json b/package.json index 92682c4..6c3d757 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "easy-github-hosts", - "version": "1.2.0", + "version": "1.3.0", "description": "Easy to add IP of GitHub into your HOSTS file.", "main": "main.js", "scripts": { "test": "node main.js --debug", - "start": "node main.js" + "start": "node main.js", + "restore": "node restoreHosts.js" }, "author": "lingbopro,Minemetero", "license": "MIT", diff --git a/restoreHosts.js b/restoreHosts.js new file mode 100644 index 0000000..da353d9 --- /dev/null +++ b/restoreHosts.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +"use strict"; + +const fs = require("fs"); +const os = require("os"); + +const appName = "Easy GitHub Hosts"; + +/** + * 恢复 HOSTS 文件的备份 + */ +function restoreHosts() { + console.log(`${appName}: Starting restoration`); + + const hostsPath = os.type().includes("Windows") ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts"; + const backupPath = `${hostsPath}.backup`; + + if (!fs.existsSync(backupPath)) { + console.error(`${appName}: ERROR - Backup file not found: ${backupPath}`); + process.exit(1); + } + + try { + fs.copyFileSync(backupPath, hostsPath); + console.log(`${appName}: Successfully restored HOSTS file from backup`); + process.exit(0); + } catch (err) { + console.error(`${appName}: ERROR - An unexpected error occurred while restoring:`, err); + process.exit(1); + } +} + +module.exports = { restoreHosts }; + +if (require.main === module) { + restoreHosts(); +} diff --git a/updateHosts.js b/updateHosts.js index 1a5a28b..1c554d6 100644 --- a/updateHosts.js +++ b/updateHosts.js @@ -5,34 +5,25 @@ const fs = require("fs"); const os = require("os"); const readline = require("readline"); +const path = require("path"); const { getIPs } = require("./ipFetcher"); const appName = "Easy GitHub Hosts"; -const debug = process.argv.indexOf("--debug") !== -1; -const noedit = process.argv.indexOf("--noedit") !== -1; -const diff = noedit && process.argv.indexOf("--diff") !== -1; -let hostsContent; -let records = []; +const debug = process.argv.includes("--debug"); +const noedit = process.argv.includes("--noedit"); +const diff = noedit && process.argv.includes("--diff"); /** - * @function checkIPv4 - * 检查给定的字符串是否为 IPv4 地址 + * 检查给定的字符串是否为有效的 IPv4 地址 * @param {string} IP - 要检查的字符串 * @returns {boolean} - 如果是有效的 IPv4 地址则返回 true,否则返回 false */ function checkIPv4(IP) { - let arr = IP.split("."); - if (arr.length !== 4) return false; - for (let i of arr) { - if (isNaN(i) || Number(i) > 255 || Number(i) < 0 || (i[0] === "0" && i.length !== 1)) { - return false; - } - } - return true; + const parts = IP.split("."); + return parts.length === 4 && parts.every(part => !isNaN(part) && Number(part) >= 0 && Number(part) <= 255); } /** - * @function parseHostsRecord * 解析一条 HOSTS 记录 * @param {string} record - 一条记录 * @returns {object} - 解析后的数据(不带行号) @@ -41,208 +32,119 @@ function parseHostsRecord(record) { if (debug) { console.log(`${appName}: (debug) Parsing HOSTS record: ${record}`); } - let splitRecord = record.split(" "); - let params = []; if (record.startsWith("#")) { - return { ip: "", host: "", description: record?.slice(1) }; - } - if (splitRecord.length < 3) { - return { ip: "", host: "", description: record ?? "" }; + return { ip: "", host: "", description: record.slice(1).trim() }; } - splitRecord.forEach(function (currentValue, index) { - if (currentValue !== "") { - params.push(currentValue); - } - }); - if (debug) { - console.debug(`${appName}: (debug) record params: ${params}`); + + const parts = record.split(/\s+/); + if (parts.length < 2) { + return { ip: "", host: "", description: record.trim() }; } - return { ip: params[0], host: params[1], description: params[2]?.slice(1) }; + + return { ip: parts[0], host: parts[1], description: parts.slice(2).join(' ').replace(/^#/, '').trim() }; } /** - * @function getHostsRecords - * 解析 HOSTS 中的所有记录 - * @param {string} content - HOSTS 的内容 - * @returns {array} - 解析后的数据(带行号) + * 解析 HOSTS 文件中的所有记录 + * @param {string} content - HOSTS 文件的内容 + * @returns {array} - 解析后的记录数组(带行号) */ function getHostsRecords(content) { - content = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x00/g, ""); - let splitContent = content.split(/\r?\n/); - let records = []; - splitContent.forEach(function (currentValue, index) { - let thisRecord = parseHostsRecord(currentValue); - if (thisRecord.ip != "" || thisRecord.description != "") { - thisRecord.line = index + 1; - records.push(thisRecord); - } - }); - return records; + return content.split(/\r?\n/) + .map((line, index) => ({ ...parseHostsRecord(line), line: index + 1 })) + .filter(record => record.ip || record.description); } /** - * @function getHostsRecordIndexByHost - * 根据域名查找 HOSTS 记录,返回第一个匹配项的索引 + * 根据域名查找 HOSTS 记录的索引 * @param {array} records - 记录列表 * @param {string} host - 域名 - * @returns {number} - 在记录列表中的索引 + * @returns {number} - 在记录列表中的索引,找不到返回 -1 */ function getHostsRecordIndexByHost(records, host) { - for (let i = 0; i < records.length; i++) { - if (records[i].host == host) { - return i; - } - } - return -1; + return records.findIndex(record => record.host === host); } /** - * @function genHosts - * 生成 HOSTS + * 生成 HOSTS 文件的内容 * @param {array} records - 记录列表 - * @returns {string} - 生成的 HOSTS + * @returns {string} - 生成的 HOSTS 文件内容 */ function genHosts(records) { - let hosts = ""; - records.forEach(function (currentValue, index) { - hosts += `${currentValue.ip}${currentValue.ip != "" ? " " : ""}` + - `${currentValue.host}${currentValue.host != "" ? " " : ""}` + - `${currentValue.description ? "#" + currentValue.description : ""}\n`; - }); - return hosts; + return records.map(record => `${record.ip} ${record.host} ${record.description ? '#' + record.description : ''}`).join('\n'); } /** - * @function sortArrayByItemProperty - * 根据数组中每个对象的属性排序数组 - * @param {array} array - 数组 - * @param {string} prop - 属性名 - * @returns {array} - 排序后的数组 + * 创建 HOSTS 文件的备份 + * @param {string} hostsPath - HOSTS 文件路径 + * @returns {string} - 备份文件路径 */ -function sortArrayByItemProperty(array, prop) { - for (let a = 0; a < array.length; a++) { - for (let b = a + 1; b < array.length; b++) { - if (array[a][prop] > array[b][prop]) { - let temp = array[a]; - array[a] = array[b]; - array[b] = temp; - } - } - } - return array; +function createBackup(hostsPath) { + const backupPath = `${hostsPath}.backup`; + fs.copyFileSync(hostsPath, backupPath); + console.log(`${appName}: Created backup at ${backupPath}`); + return backupPath; } -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout -}); - /** - * @function updateHosts * 主函数,更新 HOSTS 文件 */ -function updateHosts() { +async function updateHosts() { console.log(`${appName}: Starting`); - // 判断操作系统,选择相应的 hosts 文件路径 - const hostsPath = os.type().search("Windows") !== -1 ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts"; + const hostsPath = os.type().includes("Windows") ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts"; try { - fs.open(hostsPath, "r+", (err, data) => { - if (err) { - console.log(`${appName}: ERROR - Error opening HOSTS file:`); - console.log(err); - console.log(`${appName}: Please try running this program as Administrator (or super user).`); - console.log(`${appName}: If the error occurred again, please report an issue at https://github.com/lingbopro/easy-github-hosts/issues`); - process.exit(1); - } else { - console.log(`${appName}: Success opened HOSTS file`); - fs.read(data, (err, bytes, data) => { - if (err) { - console.log(`${appName}: ERROR - Error reading HOSTS file:`); - console.log(err); - console.log(`${appName}: Please try running this program as Administrator (or super user).`); - console.log(`${appName}: If the error occurred again, please report an issue at https://github.com/lingbopro/easy-github-hosts/issues`); - process.exit(1); - } else { - console.log(`${appName}: Success read HOSTS file (${bytes} bytes)`); - hostsContent = data.toString(); - records = getHostsRecords(hostsContent); - console.log(`${appName}: Got ${records.length} records from HOSTS file`); - getIPs() - .catch((err) => { - console.log(`${appName}: ERROR - Error getting IP:`); - console.log(err); - console.log(`${appName}: Please make sure you have a stable internet connection, and try again.`); - console.log(`${appName}: If the error occurred again, please report an issue at https://github.com/lingbopro/easy-github-hosts/issues`); - process.exit(1); - }) - .then((IPs) => { - IPs = sortArrayByItemProperty(IPs, "host"); - let newRecords = diff ? [] : JSON.parse(JSON.stringify(records)); - IPs.forEach(function (currentValue) { - if (checkIPv4(currentValue.ip)) { - let recordIndex = getHostsRecordIndexByHost(newRecords, currentValue.host); - if (recordIndex !== -1) { - newRecords[recordIndex].ip = currentValue.ip; - } else { - newRecords.push({ ip: currentValue.ip, host: currentValue.host, description: "" }); - } - } - }); - newRecords = sortArrayByItemProperty(newRecords, "line"); - const newHostsContent = genHosts(newRecords); - if (noedit) { - console.log(newHostsContent); - if (diff) { - process.exit(0); - } else { - fs.writeFile(hostsPath, newHostsContent, (err) => { - if (err) { - console.log(`${appName}: ERROR - Error writing HOSTS file:`); - console.log(err); - console.log(`${appName}: Please try running this program as Administrator (or super user).`); - console.log(`${appName}: If the error occurred again, please report an issue at https://github.com/lingbopro/easy-github-hosts/issues`); - process.exit(1); - } else { - console.log(`${appName}: Successfully updated HOSTS file`); - process.exit(0); - } - }); - } - } else { - rl.question(`${appName}: Are you sure you want to update the hosts file? (yes/no) `, (answer) => { - if (answer.toLowerCase() === "yes") { - fs.writeFile(hostsPath, newHostsContent, (err) => { - if (err) { - console.log(`${appName}: ERROR - Error writing HOSTS file:`); - console.log(err); - console.log(`${appName}: Please try running this program as Administrator (or super user).`); - console.log(`${appName}: If the error occurred again, please report an issue at https://github.com/lingbopro/easy-github-hosts/issues`); - process.exit(1); - } else { - console.log(`${appName}: Successfully updated HOSTS file`); - process.exit(0); - } - }); - } else { - console.log(`${appName}: Update cancelled`); - process.exit(0); - } - }); - } - }); - } - }); + const data = fs.readFileSync(hostsPath, 'utf-8'); + console.log(`${appName}: Successfully read HOSTS file`); + + const existingRecords = getHostsRecords(data); + console.log(`${appName}: Got ${existingRecords.length} records from HOSTS file`); + + const IPs = await getIPs(); + const newRecords = diff ? [] : [...existingRecords]; + + IPs.forEach(ipRecord => { + if (checkIPv4(ipRecord.ip)) { + const index = getHostsRecordIndexByHost(newRecords, ipRecord.host); + if (index !== -1) { + newRecords[index].ip = ipRecord.ip; + } else { + newRecords.push({ ...ipRecord, description: "" }); + } } }); + + const newHostsContent = genHosts(newRecords); + + if (noedit) { + console.log(newHostsContent); + if (diff) process.exit(0); + } else { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + rl.question(`${appName}: Are you sure you want to update the hosts file? (yes/no) `, answer => { + if (answer.toLowerCase() === 'yes') { + createBackup(hostsPath); + fs.writeFileSync(hostsPath, newHostsContent, 'utf-8'); + console.log(`${appName}: Successfully updated HOSTS file`); + } else { + console.log(`${appName}: Update cancelled`); + } + rl.close(); + }); + } } catch (err) { - console.log(`${appName}: ERROR - An unexpected error occurred:`); - console.log(err); - console.log(`${appName}: Please try running this program as Administrator (or super user).`); - console.log(`${appName}: If the error occurred again, please report an issue at https://github.com/lingbopro/easy-github-hosts/issues`); + console.error(`${appName}: ERROR - An unexpected error occurred:`, err); process.exit(1); } } module.exports = { updateHosts }; + +if (require.main === module) { + updateHosts(); +} From 752723824e7c90139fcf14a95c75e6b1d3cf2ff6 Mon Sep 17 00:00:00 2001 From: Minemetero <156386015+Minemetero@users.noreply.github.com> Date: Sun, 26 May 2024 20:40:14 +0900 Subject: [PATCH 3/6] Update README-dev.md a fix --- docs/README-dev.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/README-dev.md b/docs/README-dev.md index 0b257c4..b83458a 100644 --- a/docs/README-dev.md +++ b/docs/README-dev.md @@ -21,18 +21,18 @@ This document provides a detailed guide for developers who wish to understand, m The project has the following structure: -easy-github-hosts/ -├── .github/ -│ ├── bug_report.md -│ ├── feature_request.md -├── docs/ -│ ├── README.md -│ ├── README-dev.md -├── ipFetcher.js -├── main.js -├── package.json -├── restoreHosts.js -├── updateHosts.js +easy-github-hosts/ +├── .github/ +│ ├── bug_report.md +│ ├── feature_request.md +├── docs/ +│ ├── README.md +│ ├── README-dev.md +├── ipFetcher.js +├── main.js +├── package.json +├── restoreHosts.js +├── updateHosts.js - **.github/**: Contains the issue template files. - **bug_report.md**: Yes! It for bug report issue. @@ -82,4 +82,4 @@ Fork the repository. Create a new branch for your feature or bug fix. Commit your changes with a descriptive message. Push your branch to your fork. -Submit a pull request to the main repository **(dev branch)**. \ No newline at end of file +Submit a pull request to the main repository **(dev branch)**. From 5512a7df11055b04b55fd493b329296586cc16bc Mon Sep 17 00:00:00 2001 From: Minemetero <156386015+Minemetero@users.noreply.github.com> Date: Mon, 27 May 2024 16:50:24 +0900 Subject: [PATCH 4/6] Update README.md --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index e88ba8c..5f4fc43 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,6 @@ chmod +x main.js updateHosts.js ipFetcher.js node main.js ``` -或者: -```shell -node main.js -``` - 有 3 种可选的选项,详见[选项](#选项)。 如果写入失败,请尝试以管理员运行(Windows),或者以超级用户权限执行(`sudo`,Linux/Mac) From 0cbb4740b48abceb3e9cf5a505db4353da2420fa Mon Sep 17 00:00:00 2001 From: Minemetero <156386015+Minemetero@users.noreply.github.com> Date: Mon, 27 May 2024 16:50:53 +0900 Subject: [PATCH 5/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f4fc43..1781443 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ node main.js ### 5. 完事! #### 什么?你想改回你的Hosts文件? -~hahaha,你别想该回去了~ +~hahaha,你别想改回去了~ 恢复hosts文件 From 3d124b42db5e319d131711678ecfcd4167d0c77d Mon Sep 17 00:00:00 2001 From: Minemetero <156386015+Minemetero@users.noreply.github.com> Date: Mon, 27 May 2024 17:24:46 +0900 Subject: [PATCH 6/6] Update updateHosts.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加log声明,回复变量声明 --- updateHosts.js | 50 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/updateHosts.js b/updateHosts.js index 1c554d6..92207d3 100644 --- a/updateHosts.js +++ b/updateHosts.js @@ -5,7 +5,6 @@ const fs = require("fs"); const os = require("os"); const readline = require("readline"); -const path = require("path"); const { getIPs } = require("./ipFetcher"); const appName = "Easy GitHub Hosts"; @@ -13,6 +12,9 @@ const debug = process.argv.includes("--debug"); const noedit = process.argv.includes("--noedit"); const diff = noedit && process.argv.includes("--diff"); +let hostsContent; // 这里恢复变量声明 +let records = []; // 这里恢复变量声明 + /** * 检查给定的字符串是否为有效的 IPv4 地址 * @param {string} IP - 要检查的字符串 @@ -81,9 +83,18 @@ function genHosts(records) { */ function createBackup(hostsPath) { const backupPath = `${hostsPath}.backup`; - fs.copyFileSync(hostsPath, backupPath); - console.log(`${appName}: Created backup at ${backupPath}`); - return backupPath; + try { + fs.copyFileSync(hostsPath, backupPath); + console.log(`${appName}: Created backup at ${backupPath}`); + return backupPath; + } catch (err) { + if (err.code === 'EPERM') { + console.error(`${appName}: ERROR - Permission denied while creating backup. Please run this program as Administrator (or super user).`); + } else { + console.error(`${appName}: ERROR - Error creating backup:`, err); + } + process.exit(1); + } } /** @@ -95,14 +106,14 @@ async function updateHosts() { const hostsPath = os.type().includes("Windows") ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts"; try { - const data = fs.readFileSync(hostsPath, 'utf-8'); + hostsContent = fs.readFileSync(hostsPath, 'utf-8'); // 读取 HOSTS 文件内容 console.log(`${appName}: Successfully read HOSTS file`); - const existingRecords = getHostsRecords(data); - console.log(`${appName}: Got ${existingRecords.length} records from HOSTS file`); + records = getHostsRecords(hostsContent); // 获取 HOSTS 记录 + console.log(`${appName}: Got ${records.length} records from HOSTS file`); const IPs = await getIPs(); - const newRecords = diff ? [] : [...existingRecords]; + const newRecords = diff ? [] : [...records]; IPs.forEach(ipRecord => { if (checkIPv4(ipRecord.ip)) { @@ -129,8 +140,17 @@ async function updateHosts() { rl.question(`${appName}: Are you sure you want to update the hosts file? (yes/no) `, answer => { if (answer.toLowerCase() === 'yes') { createBackup(hostsPath); - fs.writeFileSync(hostsPath, newHostsContent, 'utf-8'); - console.log(`${appName}: Successfully updated HOSTS file`); + try { + fs.writeFileSync(hostsPath, newHostsContent, 'utf-8'); + console.log(`${appName}: Successfully updated HOSTS file`); + } catch (err) { + if (err.code === 'EPERM') { + console.error(`${appName}: ERROR - Permission denied while writing HOSTS file. Please run this program as Administrator (or super user).`); + } else { + console.error(`${appName}: ERROR - Error writing new HOSTS file:`, err); + } + process.exit(1); + } } else { console.log(`${appName}: Update cancelled`); } @@ -138,13 +158,13 @@ async function updateHosts() { }); } } catch (err) { - console.error(`${appName}: ERROR - An unexpected error occurred:`, err); + if (err.code === 'EPERM') { + console.error(`${appName}: ERROR - Permission denied while accessing HOSTS file. Please run this program as Administrator (or super user).`); + } else { + console.error(`${appName}: ERROR - An unexpected error occurred:`, err); + } process.exit(1); } } module.exports = { updateHosts }; - -if (require.main === module) { - updateHosts(); -}