feat: add home carrier information to ModemSummary interface

This commit is contained in:
MengMengCode
2026-08-14 00:22:39 +08:00
parent e546e810fe
commit 67f2ddbaeb
27 changed files with 5888 additions and 132 deletions
@@ -4,7 +4,7 @@ import { FieldRow } from "./FieldRow";
import { useShowSensitive } from "./shared";
import type { DeviceDetail } from "./types";
import { useI18n } from "../../lib/i18n";
import { carrierBrandIso } from "../../lib/carrier";
import { carrierIso } from "../../lib/carrier";
import { CountryFlag } from "../CountryFlag";
export interface OverviewSimPanelProps {
@@ -22,7 +22,7 @@ export function OverviewSimPanel({ device, simOperatorDisplay, customPhoneNumber
const sensitive = !showSensitive;
const activeEsim = (device.activeEsimProfileName || "").trim();
const flightOn = device.vowifiActive || modem?.operatingMode === 0 || modem?.operatingMode === 4;
const carrierCountryCode = carrierBrandIso(modem?.nativeSpn, modem?.imsi);
const carrierCountryCode = String(modem?.homeCarrierCountryCode ?? "").trim() || carrierIso(modem?.imsi);
const displayedPhoneNumber = customPhoneNumber?.trim() || device.localPhone || "--";
const backendLabel =
device.backendMode === "qmi" ? "QMI" : device.backendMode === "mbim" ? "MBIM" : device.backendMode === "at" ? "AT" : "Auto";
+10 -12
View File
@@ -259,20 +259,18 @@ export function simOperatorDisplay(device?: DeviceDetail | null): string {
const spn = String(modem?.nativeSpn ?? "").trim();
const name = oplPnnName(modem) || firstPnnName(modem?.pnn);
const plmn = plmnOf(modem);
// EF_SPN is the SIM's customer-facing brand. Do not append the currently
// visited PLMN: a roaming Lebara UK SIM on a Chinese network would otherwise
// be mislabeled as "Lebara (460xx)". Append the home/authentication PLMN
// resolved from IMSI instead, so GigSky on 222-01 renders as
// "GigSky (22201)" even while roaming.
if (spn) {
const home = lookupCarrier(modem?.imsi);
return withPlmn(spn, home ? home.mcc + home.mnc : cardPlmnOf(modem));
}
if (name) return withPlmn(name, plmn);
// Home ("original") carrier resolved from the SIM's IMSI via the MCC/MNC table.
// Readable even when the modem isn't camped (VoWiFi RF-off / flight mode).
// "Original Carrier" means the IMSI home/authentication network. EF_SPN is
// only a profile-supplied display brand (travel eSIMs and MVNOs may put their
// storefront name there), so it must not override a known home PLMN.
const resolvedName = String(modem?.homeCarrierName ?? "").trim();
const resolvedPLMN = String(modem?.homeCarrierPlmn ?? "").trim();
if (resolvedName) return withPlmn(resolvedName, resolvedPLMN);
const carrier = lookupCarrier(modem?.imsi);
if (carrier) return withPlmn(carrier.name, carrier.mcc + carrier.mnc);
// If the bundled carrier database cannot resolve the home PLMN, retain the
// card's own labels as graceful, data-driven fallbacks.
if (spn) return withPlmn(spn, cardPlmnOf(modem));
if (name) return withPlmn(name, plmn);
if (plmn) return plmn;
const cardPlmn = cardPlmnOf(modem);
if (cardPlmn) return cardPlmn;
@@ -21,6 +21,10 @@ function profileLabel(profile: { name?: string; serviceProviderName?: string; ic
return String(profile.name || profile.serviceProviderName || profile.iccid).trim();
}
function currentDeviceICCID(device: DeviceListItem) {
return String(device.modem?.iccid || device.vowifiRuntime?.iccid || "").trim();
}
export function DeviceBindingsDialog(props: DeviceBindingsDialogProps) {
const { t } = useI18n();
const { open, proxy, proxies, devices, bindings, busy, onAdd, onDelete, onClose } = props;
@@ -30,7 +34,7 @@ export function DeviceBindingsDialog(props: DeviceBindingsDialogProps) {
const [selected, setSelected] = useState<string[]>([]);
const proxyName = proxy?.name || proxy?.id || "";
const deviceKey = devices
.map((device) => `${device.id}:${String(device.modem?.iccid || "").trim()}`)
.map((device) => `${device.id}:${currentDeviceICCID(device)}`)
.sort()
.join("|");
const current = useMemo(
@@ -53,7 +57,7 @@ export function DeviceBindingsDialog(props: DeviceBindingsDialogProps) {
let active = true;
setLoadingProfiles(true);
Promise.allSettled(devices.map(async (device) => {
const currentICCID = String(device.modem?.iccid || "").trim();
const currentICCID = currentDeviceICCID(device);
let installed: ProfileProxyCandidate[] = [];
try {
const data = await api<EsimOverview>(`/devices/${encodeURIComponent(device.id)}/esim`);
@@ -101,7 +101,7 @@ export function NetworkAccessCard({
</Button>
</div>
<p className="text-[10px] text-gray-400">
{t("在内置内网网段之外始终放行的 CIDR 或单个 IP(例如 203.0.113.0/24)。")}
{t("在内置内网网段之外始终放行的 CIDR 或单个 IP;也允许通知推送访问这些目标地址(例如 198.18.0.0/15)。")}
</p>
{cidrs.length === 0 ? (
<div className="rounded-lg border border-dashed border-gray-200 bg-gray-50/30 py-2 text-center text-xs text-gray-400 dark:border-white/10 dark:bg-white/5">
-10
View File
@@ -47,13 +47,3 @@ export function carrierIso(imsi?: string): string {
if (hit) return hit.iso;
return data.i[imsiDigits(imsi).slice(0, 3)] ?? "";
}
// carrierBrandIso keeps the normal IMSI country flag for branded/MVNO SIMs.
// Lebara UK's Vodafone-NL-hosted 204-04 eSIM is the one known exception: its
// customer-facing country is GB even though AKA must continue using 204-04.
export function carrierBrandIso(spn?: string, imsi?: string): string {
const brand = String(spn ?? "").trim().toLowerCase();
const digits = imsiDigits(imsi);
if (brand.includes("lebara") && digits.startsWith("20404")) return "gb";
return carrierIso(imsi);
}
+2 -2
View File
@@ -352,8 +352,8 @@ export const EN_DICT: Record<string, string> = {
"Opening to the public internet greatly expands the attack surface. Use a strong password and switch back to Internal Only as soon as possible.",
: "Additional Allowed Ranges",
: "Add Range",
"在内置内网网段之外始终放行的 CIDR 或单个 IP(例如 203.0.113.0/24)。":
"CIDRs or single IPs always allowed in addition to the built-in internal ranges (e.g. 203.0.113.0/24).",
"在内置内网网段之外始终放行的 CIDR 或单个 IP;也允许通知推送访问这些目标地址(例如 198.18.0.0/15)。":
"CIDRs or single IPs always allowed in addition to the built-in internal ranges; notification delivery may also access these destinations (e.g. 198.18.0.0/15).",
: "No additional allowed ranges",
: "Trust Proxy Headers",
"仅在系统位于可信反向代理之后时开启,按 X-Forwarded-For 判定来源;否则客户端可伪造该头绕过内网限制。":
+5247 -2
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -64,6 +64,9 @@ export interface ModemSummary {
cardMcc?: string;
cardMnc?: string;
cardCountry?: string;
homeCarrierName?: string;
homeCarrierPlmn?: string;
homeCarrierCountryCode?: string;
serviceBlocked?: boolean;
blockedReason?: string;
networkMode: string;