Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v4.4 #265

Merged
merged 8 commits into from
Dec 8, 2024
Merged

v4.4 #265

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FRONTEND_PORT="18966"
ALLOWED_DOMAINS=""
# APIs
BING_MAP_API_KEY=""
GOOGLE_MAP_API_KEY=""
IPINFO_API_TOKEN=""
KEYCDN_USER_AGENT=""
CLOUDFLARE_API=""
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ You can use the program without adding any environment variables, but if you wan
| `SECURITY_RATE_LIMIT` | No | `"0"` | Controls the number of requests an IP can make to the backend server every 60 minutes (set to 0 for no limit) |
| `SECURITY_DELAY_AFTER` | No | `"0"` | Controls the first X requests from an IP every 20 minutes that are not subject to speed limits, and after X requests, the delay will increase |
| `SECURITY_BLACKLIST_LOG_FILE_PATH` | No | `"logs/blacklist-ip.log"` | Path setting. Records the list of IPs that triggered the limit after SECURITY_RATE_LIMIT is enabled |
| `BING_MAP_API_KEY` | No | `""` | API Key for Bing Maps, used to display the location of the IP on a map |
| `GOOGLE_MAP_API_KEY=` | No | `""` | API Key for Google Maps, used to display the location of the IP on a map |
| `ALLOWED_DOMAINS` | No | `""` | Allowed domains for access, separated by commas, used to prevent misuse of the backend API |
| `IPCHECKING_API_KEY` | No | `""` | API Key for IPCheck.ing, used to obtain accurate IP geolocation information |
| `IPINFO_API_TOKEN` | No | `""` | API Token for IPInfo.io, used to obtain IP geolocation information through IPInfo.io |
Expand Down Expand Up @@ -124,7 +124,7 @@ Modify `.env`, and for example, add the following:
```bash
BACKEND_PORT=11966
FRONTEND_PORT=18966
BING_MAP_API_KEY="YOUR_KEY_HERE"
GOOGLE_MAP_API_KEY="YOUR_KEY_HERE"
ALLOWED_DOMAINS="example.com"
IPCHECKING_API="YOUR_KEY_HERE"
```
Expand All @@ -137,7 +137,7 @@ You can add environment variables when running Docker, for example:

```bash
docker run -d -p 18966:18966 \
-e BING_MAP_API_KEY="YOUR_KEY_HERE" \
-e GOOGLE_MAP_API_KEY="YOUR_KEY_HERE" \
-e ALLOWED_DOMAINS="example.com" \
-e IPCHECKING_API="YOUR_TOKEN_HERE" \
--name myip \
Expand Down
6 changes: 3 additions & 3 deletions README_FR.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Vous pouvez utiliser le programme sans ajouter de variables d'environnement, mai
| `SECURITY_RATE_LIMIT` | Non | `"0"` | Contrôle le nombre de requêtes qu'une adresse IP peut faire au serveur backend toutes les 60 minutes (réglé sur 0 pour aucune limite) |
| `SECURITY_DELAY_AFTER` | Non | `"0"` | Contrôle les premières X requêtes d'une adresse IP toutes les 20 minutes qui ne sont pas soumises à des limites de vitesse, et après X requêtes, le délai augmentera |
| `SECURITY_BLACKLIST_LOG_FILE_PATH` | Non | `"logs/blacklist-ip.log"` | Paramètre de chemin. Enregistre la liste des adresses IP qui ont déclenché la limite après que `SECURITY_RATE_LIMIT` soit activé |
| `BING_MAP_API_KEY` | Non | `""` | Clé API pour Bing Maps, utilisée pour afficher l'emplacement de l'adresse IP sur une carte |
| `GOOGLE_MAP_API_KEY` | Non | `""` | Clé API pour Google Maps, utilisée pour afficher l'emplacement de l'adresse IP sur une carte |
| `ALLOWED_DOMAINS` | Non | `""` | Domaines autorisés pour l'accès, séparés par des virgules, utilisés pour empêcher une utilisation abusive de l'API backend |
| `IPCHECKING_API_KEY` | Non | `""` | Clé API pour IPCheck.ing, utilisée pour obtenir des informations de géolocalisation précises sur l'adresse IP |
| `IPINFO_API_TOKEN` | Non | `""` | Jeton API pour IPInfo.io, utilisé pour obtenir des informations de géolocalisation sur l'adresse IP via IPInfo.io |
Expand Down Expand Up @@ -124,7 +124,7 @@ Modifiez le fichier `.env`, et par exemple, ajoutez ce qui suit :
```bash
BACKEND_PORT=11966
FRONTEND_PORT=18966
BING_MAP_API_KEY="YOUR_KEY_HERE"
GOOGLE_MAP_API_KEY="YOUR_KEY_HERE"
ALLOWED_DOMAINS="example.com"
IPCHECKING_API="YOUR_KEY_HERE"
```
Expand All @@ -137,7 +137,7 @@ Vous pouvez ajouter des variables d'environnement lors de l'exécution de Docker

```bash
docker run -d -p 18966:18966 \
-e BING_MAP_API_KEY="YOUR_KEY_HERE" \
-e GOOGLE_MAP_API_KEY="YOUR_KEY_HERE" \
-e ALLOWED_DOMAINS="example.com" \
-e IPCHECKING_API="YOUR_TOKEN_HERE" \
--name myip \
Expand Down
6 changes: 3 additions & 3 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ docker run -d -p 18966:18966 --name myip --restart always jason5ng32/myip:latest
| `SECURITY_RATE_LIMIT` | 否 | `"0"` | 控制每 60 分钟一个 IP 可以对后端服务器请求的次数(设置为 0 则为不限制) |
| `SECURITY_DELAY_AFTER` | 否 | `"0"` | 控制每 20 分钟一个 IP 的前 X 次请求不受速度限制,超过 X 次后会逐次增加延迟 |
| `SECURITY_BLACKLIST_LOG_FILE_PATH` | 否 | `"logs/blacklist-ip.log"` | 路径设置。记录由 SECURITY_RATE_LIMIT 开启后,触发限制的 IP 列表 |
| `BING_MAP_API_KEY` | 否 | `""` | Bing 地图的 API Key,用于展示 IP 所在地的地图 |
| `GOOGLE_MAP_API_KEY=` | 否 | `""` | Google 地图的 API Key,用于展示 IP 所在地的地图 |
| `ALLOWED_DOMAINS` | 否 | `""` | 允许访问的域名,用逗号分隔,用于防止后端 API 被滥用 |
| `IPCHECKING_API_KEY` | 否 | `""` | IPCheck.ing 的 API Key,用于获取精准的 IP 归属地信息 |
| `IPINFO_API_TOKEN` | 否 | `""` | IPInfo.io 的 API Token,用于通过 IPInfo.io 获取 IP 归属地信息 |
Expand Down Expand Up @@ -124,7 +124,7 @@ cp .env.example .env
```bash
BACKEND_PORT=11966
FRONTEND_PORT=18966
BING_MAP_API_KEY="YOUR_KEY_HERE"
GOOGLE_MAP_API_KEY="YOUR_KEY_HERE"
ALLOWED_DOMAINS="example.com"
IPCHECKING_API="YOUR_KEY_HERE"
```
Expand All @@ -137,7 +137,7 @@ IPCHECKING_API="YOUR_KEY_HERE"

```bash
docker run -d -p 18966:18966 \
-e BING_MAP_API_KEY="YOUR_KEY_HERE" \
-e GOOGLE_MAP_API_KEY="YOUR_KEY_HERE" \
-e ALLOWED_DOMAINS="example.com" \
-e IPCHECKING_API="YOUR_TOKEN_HERE" \
--name myip \
Expand Down
2 changes: 1 addition & 1 deletion api/configs.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default (req, res) => {
const originalSite = hostname === 'ipcheck.ing' || hostname === 'www.ipcheck.ing' || hostname === 'localtest.ipcheck.ing';

const envConfigs = {
bingMap: process.env.BING_MAP_API_KEY,
map: process.env.GOOGLE_MAP_API_KEY,
ipInfo: process.env.IPINFO_API_TOKEN,
ipChecking: process.env.IPCHECKING_API_KEY,
keyCDN: process.env.KEYCDN_USER_AGENT,
Expand Down
45 changes: 35 additions & 10 deletions api/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,42 @@ import { get } from 'https';
import { refererCheck } from '../common/referer-check.js';

// 验证请求合法性

function isValidRequest(req) {

const isLatitudeValid = /^-?\d+(\.\d+)?$/.test(req.query.latitude);
const isLongitudeValid = /^-?\d+(\.\d+)?$/.test(req.query.longitude);
const isLanguageValid = /^[a-z]{2}$/.test(req.query.language);
const isCanvasModeValid = /^(CanvasLight|RoadDark)$/.test(req.query.CanvasMode);

if (!isLatitudeValid || !isLongitudeValid || !isLanguageValid || !isCanvasModeValid) {
if (!isLatitudeValid || !isLongitudeValid || !isLanguageValid) {
return false;
} else {
return true;
}
}

// 定义白天模式和黑暗模式样式字符串
const styles = {
Dark: [
"feature:all|element:geometry.fill|color:0x242f3e",
"feature:all|element:labels.text.stroke|color:0x242f3e",
"feature:all|element:labels.text.fill|color:0x746855",
"feature:administrative.locality|element:labels.text.fill|color:0xd59563",
"feature:poi|element:labels.text.fill|color:0xd59563",
"feature:poi.park|element:geometry|color:0x263c3f",
"feature:poi.park|element:labels.text.fill|color:0x6b9a76",
"feature:road|element:geometry|color:0x38414e",
"feature:road|element:geometry.stroke|color:0x212a37",
"feature:road|element:labels.text.fill|color:0x9ca5b3",
"feature:road.highway|element:geometry|color:0x746855",
"feature:road.highway|element:geometry.stroke|color:0x1f2835",
"feature:road.highway|element:labels.text.fill|color:0xf3d19c",
"feature:transit|element:geometry|color:0x2f3948",
"feature:transit.station|element:labels.text.fill|color:0xd59563",
"feature:water|element:geometry|color:0x17263c",
"feature:water|element:labels.text.fill|color:0x515c6d",
"feature:all|element:labels.text.stroke|color:0x17263c"
]
};

export default (req, res) => {
// 限制只能从指定域名访问
const referer = req.headers.referer;
Expand All @@ -36,16 +57,20 @@ export default (req, res) => {
return res.status(400).json({ error: 'Missing latitude, longitude, or language' });
}

const mapSize = '800,640';
const pp = `${latitude},${longitude};46`;
const fmt = 'jpeg';
const dpi = 'Large';
const mapSize = '500x400';
const fmt = 'jpg';
const scale = 2;
const zoom = 3;

const apiKeys = (process.env.BING_MAP_API_KEY || '').split(',');
const apiKeys = (process.env.GOOGLE_MAP_API_KEY || '').split(',');
const apiKey = apiKeys[Math.floor(Math.random() * apiKeys.length)];

const url = `https://dev.virtualearth.net/REST/v1/Imagery/Map/${CanvasMode}/${latitude},${longitude}/5?mapSize=${mapSize}&pp=${pp}&key=${apiKey}&fmt=${fmt}&dpi=${dpi}&c=${language}`;
let styleParam = '';
if (CanvasMode === 'Dark') {
styleParam = styles.Dark.join('&style=');
}

const url = `https://maps.googleapis.com/maps/api/staticmap?center=${latitude},${longitude}&markers=color:blue%7C${latitude},${longitude}&scale=${scale}&zoom=${zoom}&maptype=roadmap&language=${language}&format=${fmt}&size=${mapSize}&style=${styleParam}&key=${apiKey}`;

get(url, apiRes => {
apiRes.pipe(res);
Expand Down
2 changes: 1 addition & 1 deletion frontend/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ const ShortcutKeys = (isOriginalSite) => {
{
keys: "m",
action: () => {
if (configs.value.bingMap) {
if (configs.value.map) {
window.scrollTo({ top: 0, behavior: "smooth" });
preferencesRef.value.toggleMaps();
};
Expand Down
15 changes: 0 additions & 15 deletions frontend/components/Nav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,6 @@
}">ing</span>
</a>

<div class="btn-group mx-1" :data-bs-theme="isDarkMode ? 'dark' : 'light'">
<button type="button" class="btn btn-sm dropdown-toggle jn-button" data-bs-toggle="dropdown"
aria-expanded="false" aria-label="Language Selection">
<i class="bi bi-translate"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="?hl=zh" @click="trackEvent('Nav', 'ToggleClick', 'LanguageChange')"><i
class="fi fi-cn"></i> 中文</a></li>
<li><a class="dropdown-item" href="?hl=en" @click="trackEvent('Nav', 'ToggleClick', 'LanguageChange')"><i
class="fi fi-us"></i> English</a></li>
<li><a class="dropdown-item" href="?hl=fr" @click="trackEvent('Nav', 'ToggleClick', 'LanguageChange')"><i
class="fi fi-fr"></i> Français</a></li>
</ul>
</div>

<div id="Preferences" class="preference-button" @click.prevent="OpenPreferences" role="button"
aria-label="Preferences">
<i class="bi bi-toggles"></i>
Expand Down
47 changes: 38 additions & 9 deletions frontend/components/widgets/Preferences.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,32 @@
<div class="offcanvas-body pt-0 m-2">
<div class="preferences-tip">{{ t('nav.preferences.preferenceTips') }}</div>

<!-- 语言设置 -->

<div id="Pref_language">
<div class="form-label col-12 preferences-title"><i class="bi bi-translate"></i> {{
t('nav.preferences.language') }}</div>
<div class="btn-group-vertical col-auto w-50 mb-2" role="group" aria-label="Color Scheme">
<template v-for="lang in ['auto','zh', 'en', 'fr']">
<input type="radio" class="btn-check" :name="'language' + lang" :id="'language' + lang"
autocomplete="off" :value="lang" v-model="userPreferences.lang"
@change="prefLanguage(lang)">
<label class="btn jn-number text-start" :class="{
'btn-outline-dark': !isDarkMode,
'btn-outline-light': isDarkMode,
'active fw-bold': userPreferences.lang === lang
}" :for="'language' + lang">
<span v-if="lang === 'zh'"><i class="fi fi-cn"></i> 中文&nbsp;</span>
<span v-else-if="lang === 'en'"><i class="fi fi-us"></i> English&nbsp;</span>
<span v-else-if="lang === 'fr'"><i class="fi fi-fr"></i> Français&nbsp;</span>
<span v-else>{{ t('nav.preferences.systemAuto') }}&nbsp;</span>
<i class="bi bi-check2-circle" v-if="userPreferences.lang === lang"></i>
</label>
</template>
</div>
<div class="preferences-tip">{{ t('nav.preferences.languageTips') }}</div>
</div>

<!-- 主题方案 -->

<div id="Pref_colorScheme">
Expand All @@ -31,7 +57,7 @@
t('nav.preferences.colorLight') }}</span>
<span v-else-if="theme === 'dark'"><i class="bi bi-moon-stars"></i> {{
t('nav.preferences.colorDark') }}</span>
<span v-else>{{ t('nav.preferences.colorAuto') }}</span>
<span v-else>{{ t('nav.preferences.systemAuto') }}</span>
</label>
</template>
</div>
Expand Down Expand Up @@ -94,7 +120,7 @@
:class="[isDarkMode ? 'border-light' : 'border-dark']">
<div class="me-auto">
<div class="fw-bold"><label class="form-check-label" for="autoStart">{{
t('nav.preferences.autoRun')
t('nav.preferences.autoRun')
}}</label>
</div>
<div class="preferences-tip">{{ t('nav.preferences.autoRunTips') }}</div>
Expand All @@ -110,7 +136,7 @@
:class="[isDarkMode ? 'border-light' : 'border-dark']" v-if="userPreferences.autoStart">
<div class="me-auto">
<div class="fw-bold"><label class="form-check-label" for="ConnectivityRefresh">{{
t('nav.preferences.connectivityAutoRefresh') }}</label></div>
t('nav.preferences.connectivityAutoRefresh') }}</label></div>
<div class="preferences-tip">{{ t('nav.preferences.connectivityAutoRefreshTips') }}</div>
</div>
<div class="form-check form-switch col-auto ">
Expand All @@ -122,10 +148,10 @@
</li>

<li class="list-group-item d-flex justify-content-between align-items-start"
:class="[isDarkMode ? 'border-light' : 'border-dark']" v-if="configs.bingMap">
:class="[isDarkMode ? 'border-light' : 'border-dark']" v-if="configs.map">
<div class="me-auto">
<div class="fw-bold"><label class="form-check-label" for="showMap">{{
t('nav.preferences.showMap')
t('nav.preferences.showMap')
}}</label>
</div>
<div class="preferences-tip">{{ t('nav.preferences.showMapTips') }}</div>
Expand All @@ -141,7 +167,7 @@
:class="[isDarkMode ? 'border-light' : 'border-dark']" v-if="isMobile">
<div class="me-auto">
<div class="fw-bold"><label class="form-check-label" for="simpleMode">{{
t('nav.preferences.simpleMode')
t('nav.preferences.simpleMode')
}}</label></div>
<div class="preferences-tip">{{ t('nav.preferences.simpleModeTips') }}</div>
</div>
Expand All @@ -156,7 +182,7 @@
:class="[isDarkMode ? 'border-light' : 'border-dark']">
<div class="me-auto">
<div class="fw-bold"><label class="form-check-label" for="ConnectivityNotifications">{{
t('nav.preferences.popupConnectivityNotifications') }}</label>
t('nav.preferences.popupConnectivityNotifications') }}</label>
</div>
<div class="preferences-tip">{{ t('nav.preferences.popupConnectivityNotificationsTips') }}
</div>
Expand Down Expand Up @@ -186,7 +212,7 @@ import { useMainStore } from '@/store';
import { useI18n } from 'vue-i18n';
import { trackEvent } from '@/utils/use-analytics';

const {t} = useI18n();
const { t } = useI18n();

const store = useMainStore();
const isDarkMode = computed(() => store.isDarkMode);
Expand Down Expand Up @@ -252,7 +278,10 @@ const prefTheme = (value) => {
trackEvent('Nav', 'PreferenceClick', 'Theme');
};


const prefLanguage = (value) => {
store.updatePreference('lang', value);
trackEvent('Nav', 'PrefereceClick', 'LanguageChange');
};

const prefConnectivityRefresh = (value) => {
store.updatePreference('connectivityAutoRefresh', value);
Expand Down
24 changes: 22 additions & 2 deletions frontend/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"title": "Preferences",
"preferenceTips": "These settings are saved in your browser for easy reuse. Some options require refreshing the page to take effect.",
"colorScheme": "Color Scheme",
"colorAuto": "Auto",
"systemAuto": "Auto",
"colorLight": "Day",
"colorDark": "Night",
"ipSourcesToCheck": "Servers To Check IPs",
Expand All @@ -32,7 +32,9 @@
"popupConnectivityNotifications": "Pop-up Connectivity Alerts",
"popupConnectivityNotificationsTips": "When enabled, the initial check's results are shown as a pop-up alert.",
"ipDB": "IP Geolocation Database",
"ipDBTips": "You can select the default IP geolocation source to use. If the selected source is unavailable, the system will use the subsequent sources in order."
"ipDBTips": "You can select the default IP geolocation source to use. If the selected source is unavailable, the system will use the subsequent sources in order.",
"language": "Language Setting",
"languageTips": "Refreshing the browser will take effect."
}
},
"shell": {
Expand Down Expand Up @@ -887,6 +889,24 @@
"change": "DNS leak test can now display regional information"
}
]
},
{
"version": "v4.4",
"date": "Dec 7, 2024",
"content": [
{
"type": "add",
"change": "Language preferences"
},
{
"type": "improve",
"change": "Map provider changed to Google"
},
{
"type": "improve",
"change": "Other general optimizations"
}
]
}
]
}
Expand Down
Loading
Loading