4.1.3
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
decryptText,
|
||||
deriveDmAesKey,
|
||||
encryptText,
|
||||
importPublicKeySpkiB64,
|
||||
} from "./crypto";
|
||||
import { E2EE_LOCKED_PREVIEW, isE2eeEnvelope } from "./envelope";
|
||||
@@ -78,24 +77,19 @@ export function clearDmKeyCache(): void {
|
||||
dmKeyCache.clear();
|
||||
}
|
||||
|
||||
// دوباره فعال شده — حالا که بکآپِ کلید با PIN (keys.ts: saveKeyBackup/
|
||||
// recoverIdentityFromBackup) و چکِ ایمنِ «هویتِ قبلی روی سرور هست ولی این دستگاه
|
||||
// کلیدِ محلی نداره» (keys.ts: IdentityRecoveryNeededError) قبل از این وجود دارن، یه
|
||||
// کلیدِ محلی هیچوقت بیصدا جایگزینِ یه هویتِ قدیمی نمیشه. اگه کلیدِ طرفِ مقابل در
|
||||
// دسترس نباشه (fail شدنِ getDmConversationKey)، متنِ ساده ارسال میشه — بهتر از
|
||||
// شکستِ کاملِ ارسالِ پیام، ولی این حالت باید نادر باشه
|
||||
// موقتاً غیرفعال شده بهدرخواستِ کاربر — با اینکه زیرساختِ بازیابیِ خودکار (رمزِ
|
||||
// per-account، keys.ts: tryAutoRecoverIdentity) طبق طراحی دقیقاً همون رفتارِ
|
||||
// «بدونِ رمزِ دستی مثلِ واتساپ» رو داشت، هنوز موردهایی بود که طرفِ مقابل همچنان
|
||||
// «پیام رمزنگاریشده» میدید (هم توی وب هم اندروید). تا زمانی که با لاگِ واقعی
|
||||
// ریشهیابی و رفع بشه، پیامهای جدید ساده (بدونِ envelope) ارسال میشن —
|
||||
// decryptDmContent برای پیامهای قدیمیِ رمزنگاریشده دستنخورده مونده. کلِ زیرساختِ
|
||||
// کلید/بکآپ دستنخورده مونده تا بعداً دوباره همینجا فعال بشه (فقط همین return رو بردار)
|
||||
export async function encryptDmContent(
|
||||
myUserId: string,
|
||||
peerUserId: string,
|
||||
plaintext: string
|
||||
): Promise<string | null> {
|
||||
const key = await getDmConversationKey(myUserId, peerUserId);
|
||||
if (!key) return plaintext;
|
||||
try {
|
||||
return encryptText(key, plaintext);
|
||||
} catch {
|
||||
return plaintext;
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
export async function decryptDmContent(
|
||||
|
||||
@@ -2,7 +2,6 @@ import Cookies from "js-cookie";
|
||||
import { getApiBaseUrl } from "@/components/main/BaseUrl";
|
||||
import {
|
||||
decryptText,
|
||||
encryptText,
|
||||
generateRoomKeyRaw,
|
||||
importPublicKeySpkiB64,
|
||||
importRoomAesKey,
|
||||
@@ -224,16 +223,15 @@ export async function ensureRoomAesKey(
|
||||
return task;
|
||||
}
|
||||
|
||||
// موقتاً غیرفعال شده بهدرخواستِ کاربر — عینِ همون دلیلِ encryptDmContent (dm.ts).
|
||||
// پیامهای جدیدِ روم ساده ارسال میشن؛ decryptRoomContent برای پیامهای قدیمیِ
|
||||
// رمزنگاریشده دستنخورده میمونه. برای فعالسازیِ دوباره، همین return رو بردار.
|
||||
export async function encryptRoomContent(
|
||||
myUserId: string,
|
||||
roomId: string,
|
||||
plaintext: string,
|
||||
): Promise<string | null> {
|
||||
if (!plaintext) return plaintext;
|
||||
if (isE2eeEnvelope(plaintext)) return plaintext;
|
||||
const key = await ensureRoomAesKey(myUserId, roomId);
|
||||
if (!key) return null;
|
||||
return encryptText(key, plaintext);
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
export async function decryptRoomContent(
|
||||
|
||||
@@ -13,7 +13,6 @@ export const RELATIONSHIP_GOAL_VALUES = [
|
||||
"not_sure",
|
||||
] as const;
|
||||
export type RelationshipGoal = (typeof RELATIONSHIP_GOAL_VALUES)[number];
|
||||
export const RELATIONSHIP_GOAL_MAX = 2;
|
||||
|
||||
export const MARITAL_STATUS_NEW_VALUES = [
|
||||
"widowed",
|
||||
@@ -69,7 +68,6 @@ export const PERSONALITY_TRAIT_VALUES = [
|
||||
"extrovert",
|
||||
] as const;
|
||||
export type PersonalityTrait = (typeof PERSONALITY_TRAIT_VALUES)[number];
|
||||
export const PERSONALITY_TRAITS_MAX = 8;
|
||||
|
||||
export const LIFESTYLE_VALUES = [
|
||||
"active_healthy",
|
||||
@@ -83,7 +81,6 @@ export const LIFESTYLE_VALUES = [
|
||||
"luxury_lover",
|
||||
] as const;
|
||||
export type Lifestyle = (typeof LIFESTYLE_VALUES)[number];
|
||||
export const LIFESTYLE_MAX = 5;
|
||||
|
||||
export const INTEREST_VALUES = [
|
||||
"movies_series",
|
||||
@@ -102,7 +99,6 @@ export const INTEREST_VALUES = [
|
||||
"language_learning",
|
||||
] as const;
|
||||
export type Interest = (typeof INTEREST_VALUES)[number];
|
||||
export const INTERESTS_MAX = 8;
|
||||
|
||||
export const VALUE_VALUES = [
|
||||
"family",
|
||||
@@ -115,7 +111,6 @@ export const VALUE_VALUES = [
|
||||
"excitement_new_experiences",
|
||||
] as const;
|
||||
export type ValueItem = (typeof VALUE_VALUES)[number];
|
||||
export const VALUES_MAX = 5;
|
||||
|
||||
export const RELATIONSHIP_VIEW_VALUES = [
|
||||
"traditional",
|
||||
@@ -146,6 +141,16 @@ export const CHILDREN_STATUS_VALUES = [
|
||||
] as const;
|
||||
export type ChildrenStatus = (typeof CHILDREN_STATUS_VALUES)[number];
|
||||
|
||||
export const PERSONAL_STYLE_VALUES = [
|
||||
"casual",
|
||||
"classic",
|
||||
"minimal",
|
||||
"formal",
|
||||
"street",
|
||||
"romantic",
|
||||
] as const;
|
||||
export type PersonalStyle = (typeof PERSONAL_STYLE_VALUES)[number];
|
||||
|
||||
export const SMOKING_STATUS_VALUES = [
|
||||
"none",
|
||||
"sometimes",
|
||||
@@ -213,12 +218,109 @@ export const buildGeoPreferenceOptions = (t: TranslateFn) =>
|
||||
export const buildChildrenStatusOptions = (t: TranslateFn) =>
|
||||
buildOptions(t, "childrenStatusOptions", CHILDREN_STATUS_VALUES);
|
||||
|
||||
export const buildPersonalStyleOptions = (t: TranslateFn) =>
|
||||
buildOptions(t, "personalStyleOptions", PERSONAL_STYLE_VALUES);
|
||||
|
||||
export const buildSmokingStatusOptions = (t: TranslateFn) =>
|
||||
buildOptions(t, "smokingStatusOptions", SMOKING_STATUS_VALUES);
|
||||
|
||||
export const buildIncomeRangeOptions = (t: TranslateFn) =>
|
||||
buildOptions(t, "incomeRangeOptions", INCOME_RANGE_VALUES);
|
||||
|
||||
/** یک دستهی بازهی عددی برای دراپداونهای قد/وزن/سن در فیلتر «یافتن پارتنر»:
|
||||
* value منحصربهفرد برای <select>، min/max برای اِعمال روی فیلتر واقعی (خالی
|
||||
* یعنی نامحدود از آن سمت). گزینهی ویژهی "custom" (بازهی انتخابی) در پایان هر
|
||||
* لیست باعث میشود دو ورودی حداقل/حداکثر دستی نمایش داده شوند. */
|
||||
export type RangeBucket = { value: string; min?: number; max?: number };
|
||||
|
||||
function buildRangeBucketLabel(t: TranslateFn, bucket: RangeBucket): string {
|
||||
if (bucket.value === "not_important") {
|
||||
return t("filters.notImportant");
|
||||
}
|
||||
if (bucket.value === "custom") {
|
||||
return t("filters.customRange");
|
||||
}
|
||||
if (bucket.min !== undefined && bucket.max !== undefined) {
|
||||
return t("filters.rangeValue", { min: bucket.min, max: bucket.max });
|
||||
}
|
||||
if (bucket.max !== undefined) {
|
||||
return t("filters.underValue", { value: bucket.max + 1 });
|
||||
}
|
||||
if (bucket.min !== undefined) {
|
||||
return t("filters.overValue", { value: bucket.min - 1 });
|
||||
}
|
||||
return bucket.value;
|
||||
}
|
||||
|
||||
export function buildRangeBucketOptions(t: TranslateFn, buckets: RangeBucket[]): LabeledOption[] {
|
||||
return buckets.map((bucket) => ({ value: bucket.value, label: buildRangeBucketLabel(t, bucket) }));
|
||||
}
|
||||
|
||||
export const HEIGHT_BUCKETS: RangeBucket[] = [
|
||||
{ value: "under_160", max: 159 },
|
||||
{ value: "160_165", min: 160, max: 165 },
|
||||
{ value: "165_170", min: 165, max: 170 },
|
||||
{ value: "170_175", min: 170, max: 175 },
|
||||
{ value: "175_180", min: 175, max: 180 },
|
||||
{ value: "180_185", min: 180, max: 185 },
|
||||
{ value: "185_190", min: 185, max: 190 },
|
||||
{ value: "190_195", min: 190, max: 195 },
|
||||
{ value: "over_195", min: 196 },
|
||||
{ value: "not_important" },
|
||||
{ value: "custom" },
|
||||
];
|
||||
|
||||
export const WEIGHT_BUCKETS: RangeBucket[] = [
|
||||
{ value: "40_45", min: 40, max: 45 },
|
||||
{ value: "45_50", min: 45, max: 50 },
|
||||
{ value: "50_55", min: 50, max: 55 },
|
||||
{ value: "55_60", min: 55, max: 60 },
|
||||
{ value: "60_65", min: 60, max: 65 },
|
||||
{ value: "65_70", min: 65, max: 70 },
|
||||
{ value: "70_75", min: 70, max: 75 },
|
||||
{ value: "75_80", min: 75, max: 80 },
|
||||
{ value: "80_85", min: 80, max: 85 },
|
||||
{ value: "85_90", min: 85, max: 90 },
|
||||
{ value: "90_95", min: 90, max: 95 },
|
||||
{ value: "over_95", min: 96 },
|
||||
{ value: "not_important" },
|
||||
{ value: "custom" },
|
||||
];
|
||||
|
||||
export const AGE_BUCKETS: RangeBucket[] = [
|
||||
{ value: "18_24", min: 18, max: 24 },
|
||||
{ value: "25_30", min: 25, max: 30 },
|
||||
{ value: "31_35", min: 31, max: 35 },
|
||||
{ value: "36_40", min: 36, max: 40 },
|
||||
{ value: "41_50", min: 41, max: 50 },
|
||||
{ value: "over_50", min: 51 },
|
||||
{ value: "not_important" },
|
||||
{ value: "custom" },
|
||||
];
|
||||
|
||||
/** سایز، برخلاف قد/وزن/سن، بازه نیست — هر گزینه یک مقدار دقیق است (min=max)،
|
||||
* عیناً سایزبندی لباس/کفشِ استفادهشده در این اپ. */
|
||||
export const SIZE_BUCKETS: RangeBucket[] = [
|
||||
34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70,
|
||||
].map((n) => ({ value: String(n), min: n, max: n }));
|
||||
export const SIZE_BUCKETS_WITH_EXTRAS: RangeBucket[] = [
|
||||
...SIZE_BUCKETS,
|
||||
{ value: "not_important" },
|
||||
{ value: "custom" },
|
||||
];
|
||||
|
||||
export function buildSizeBucketOptions(t: TranslateFn): LabeledOption[] {
|
||||
return SIZE_BUCKETS_WITH_EXTRAS.map((bucket) => ({
|
||||
value: bucket.value,
|
||||
label:
|
||||
bucket.value === "not_important"
|
||||
? t("filters.notImportant")
|
||||
: bucket.value === "custom"
|
||||
? t("filters.customRange")
|
||||
: bucket.value,
|
||||
}));
|
||||
}
|
||||
|
||||
/** برای درج n آیتم آرایهای در URLSearchParams طبق قرارداد بکاند (مقدار جدا شده با کاما). */
|
||||
export function joinFilterValues(values: string[] | undefined | null): string | undefined {
|
||||
if (!values || values.length === 0) return undefined;
|
||||
|
||||
@@ -8,10 +8,6 @@ export const PWA_THEME_COLOR = "#FF107D";
|
||||
export const PWA_BACKGROUND_COLOR = "#FF107D";
|
||||
export const PWA_ID = "modstagram-pwa";
|
||||
export const PWA_VERSION = "12";
|
||||
// نسخهی فعلیِ APK اندروید — با هر انتشار نسخهی جدید (و آپلود APK جدید توی
|
||||
// storage/downloads/modstagram.apk) این مقدار هم دستی بهروز بشه؛ همون versionName
|
||||
// توی android/app/build.gradle
|
||||
export const ANDROID_APP_VERSION = "2.1.2";
|
||||
|
||||
export { resolvePwaLang, toPwaLang } from "@/lib/i18n/pwaLang";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user