Skip to content

Commit

Permalink
Merge pull request #265 from jason5ng32/dev
Browse files Browse the repository at this point in the history
v4.4
  • Loading branch information
jason5ng32 authored Dec 8, 2024
2 parents 7616547 + ddb26e3 commit 0795caa
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 73 deletions.
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

0 comments on commit 0795caa

Please sign in to comment.