@@ -6,20 +6,34 @@ import { cn } from '@/lib/utils'
66import { getAuthToken } from '@/utils/authStorage'
77
88const DONATION_STORAGE_KEY = 'donation_popup_data'
9- const DAYS_BETWEEN_SHOWS = 3
109const FIRST_SHOW_DELAY = 10 * 60 * 1000 // 10 minutes in milliseconds
1110const SUBSEQUENT_SHOW_DELAY = 5000 // 5 seconds for subsequent shows
1211const SECRET_SALT = 'pasarguard_donation_v1' // Simple salt for checksum
1312
1413interface DonationData {
1514 lastShown : string | null
1615 nextShowTime : string
16+ showCount : number
1717 checksum : string
1818}
1919
20+ // Calculate delay in days based on show count (progressive delays)
21+ const getDelayDays = ( showCount : number ) : number => {
22+ switch ( showCount ) {
23+ case 0 :
24+ return 3 // First show: 3 days
25+ case 1 :
26+ return 7 // Second show: 7 days
27+ case 2 :
28+ return 14 // Third show: 14 days
29+ default :
30+ return 30 // Fourth show and beyond: 30 days (1 month)
31+ }
32+ }
33+
2034// Simple hash function for tamper detection
21- const generateChecksum = ( lastShown : string | null , nextShowTime : string ) : string => {
22- const data = `${ lastShown || 'null' } _${ nextShowTime } _${ SECRET_SALT } `
35+ const generateChecksum = ( lastShown : string | null , nextShowTime : string , showCount : number ) : string => {
36+ const data = `${ lastShown || 'null' } _${ nextShowTime } _${ showCount } _ ${ SECRET_SALT } `
2337 let hash = 0
2438 for ( let i = 0 ; i < data . length ; i ++ ) {
2539 const char = data . charCodeAt ( i )
@@ -32,12 +46,18 @@ const generateChecksum = (lastShown: string | null, nextShowTime: string): strin
3246// Validate data integrity and reasonableness
3347const validateData = ( data : DonationData ) : boolean => {
3448 // Check checksum
35- const expectedChecksum = generateChecksum ( data . lastShown , data . nextShowTime )
49+ const expectedChecksum = generateChecksum ( data . lastShown , data . nextShowTime , data . showCount ?? 0 )
3650 if ( data . checksum !== expectedChecksum ) {
3751 console . warn ( 'Donation popup: Data tampering detected (checksum mismatch)' )
3852 return false
3953 }
4054
55+ // Validate showCount is a non-negative integer
56+ if ( typeof data . showCount !== 'number' || data . showCount < 0 || ! Number . isInteger ( data . showCount ) ) {
57+ console . warn ( 'Donation popup: Invalid showCount' )
58+ return false
59+ }
60+
4161 // Validate timestamps are valid dates
4262 const nextShowTimestamp = new Date ( data . nextShowTime ) . getTime ( )
4363 if ( isNaN ( nextShowTimestamp ) ) {
@@ -58,8 +78,9 @@ const validateData = (data: DonationData): boolean => {
5878 return false
5979 }
6080
61- // Validate: nextShowTime shouldn't be more than 4 days after lastShown (max 3 days + 1 day buffer)
62- const maxExpectedNext = lastShownTimestamp + 4 * 24 * 60 * 60 * 1000
81+ // Validate: nextShowTime should match expected delay based on showCount
82+ const expectedDelayDays = getDelayDays ( data . showCount )
83+ const maxExpectedNext = lastShownTimestamp + ( expectedDelayDays + 1 ) * 24 * 60 * 60 * 1000 // +1 day buffer
6384 if ( nextShowTimestamp > maxExpectedNext ) {
6485 console . warn ( 'Donation popup: nextShowTime too far in future' )
6586 return false
@@ -81,7 +102,7 @@ const validateData = (data: DonationData): boolean => {
81102
82103// localStorage helper functions
83104const setStorageData = ( data : Omit < DonationData , 'checksum' > ) => {
84- const checksum = generateChecksum ( data . lastShown , data . nextShowTime )
105+ const checksum = generateChecksum ( data . lastShown , data . nextShowTime , data . showCount ?? 0 )
85106 const fullData : DonationData = { ...data , checksum }
86107 localStorage . setItem ( DONATION_STORAGE_KEY , JSON . stringify ( fullData ) )
87108}
@@ -90,14 +111,19 @@ const getStorageData = (): DonationData | null => {
90111 const stored = localStorage . getItem ( DONATION_STORAGE_KEY )
91112 if ( ! stored ) return null
92113 try {
93- const data = JSON . parse ( stored ) as DonationData
114+ const data = JSON . parse ( stored ) as Partial < DonationData >
115+ // Handle backward compatibility: if showCount is missing, default to 0
116+ const fullData : DonationData = {
117+ ...data ,
118+ showCount : data . showCount ?? 0 ,
119+ } as DonationData
94120 // Validate data integrity
95- if ( ! validateData ( data ) ) {
121+ if ( ! validateData ( fullData ) ) {
96122 // Tampering detected, clear invalid data
97123 localStorage . removeItem ( DONATION_STORAGE_KEY )
98124 return null
99125 }
100- return data
126+ return fullData
101127 } catch {
102128 return null
103129 }
@@ -110,11 +136,18 @@ export default function DonationPopup() {
110136
111137 const showPopup = useCallback ( ( ) => {
112138 const now = Date . now ( )
113- // Update storage: set lastShown to now and nextShowTime to 3 days from now
114- const nextShowTime = new Date ( now + DAYS_BETWEEN_SHOWS * 24 * 60 * 60 * 1000 ) . toISOString ( )
139+ const data = getStorageData ( )
140+ const currentShowCount = data ?. showCount ?? 0
141+
142+ // Calculate next delay based on current show count
143+ const delayDays = getDelayDays ( currentShowCount )
144+ const nextShowTime = new Date ( now + delayDays * 24 * 60 * 60 * 1000 ) . toISOString ( )
145+
146+ // Update storage: increment showCount and set nextShowTime based on progressive delay
115147 setStorageData ( {
116148 lastShown : new Date ( now ) . toISOString ( ) ,
117149 nextShowTime,
150+ showCount : currentShowCount + 1 ,
118151 } )
119152
120153 // Make visible immediately
@@ -139,9 +172,9 @@ export default function DonationPopup() {
139172 const now = Date . now ( )
140173
141174 if ( ! data ) {
142- // First time - schedule for 1 hour from now and store it
175+ // First time - schedule for initial delay and store it with showCount 0
143176 const nextShowTime = new Date ( now + FIRST_SHOW_DELAY ) . toISOString ( )
144- setStorageData ( { lastShown : null , nextShowTime } )
177+ setStorageData ( { lastShown : null , nextShowTime, showCount : 0 } )
145178 setTimeout ( ( ) => showPopup ( ) , FIRST_SHOW_DELAY )
146179 return
147180 }
0 commit comments