feat: rewarded ads thing so free user can also enjoy ad free#1918
feat: rewarded ads thing so free user can also enjoy ad free#1918bajrangCoder wants to merge 5 commits intoAcode-Foundation:mainfrom
Conversation
Greptile SummaryThis PR implements a rewarded ads system allowing free users to watch ads in exchange for temporary ad-free time. Users can choose between two offers: Quick pass (1 ad = 1 hour) or Focus block (2 ads = 4-6 hours random). The system enforces daily limits (3 redemptions/day) and caps active ad-free time at 10 hours. Key Changes:
Issues Found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
actor User
participant UI as Ad Rewards Page
participant AR as adRewards.js
participant AdMob as AdMob SDK
participant Native as Authenticator.java
participant Storage as Encrypted Prefs
User->>UI: Click "Watch ad" button
UI->>AR: watchOffer(offerId)
AR->>Native: getStatus()
Native->>Storage: Load reward state
Storage-->>Native: Current state
Native-->>AR: Validate limits
alt Daily limit reached or 10h max exceeded
AR-->>UI: Show error message
else Can redeem
loop For each ad in offer (1 or 2)
AR->>AdMob: createRewardedAd()
AR->>AdMob: load()
AR->>AdMob: show()
AdMob-->>User: Display ad
User->>AdMob: Watch & complete ad
AdMob-->>AR: Fire "reward" event
AdMob->>Google: Server-side verification (async)
end
AR->>Native: redeem(offerId)
Native->>Native: Check limits & calculate duration
Native->>Storage: Save updated state
Storage-->>Native: Success
Native-->>AR: New state with expiry time
AR->>AR: Hide active banner ads
AR->>AR: Schedule expiry check
AR-->>UI: Show success notification
UI-->>User: "X hours unlocked" message
end
Last reviewed commit: cede731 |
| async function createRewardedAd(offer, step, sessionId) { | ||
| const rewardedUnitId = getRewardedUnitId(); | ||
| if (!rewardedUnitId || !admob?.RewardedAd) { | ||
| throw new Error("Rewarded ads are not available in this build."); | ||
| } | ||
|
|
||
| const userId = await getRewardIdentity(); | ||
| const customData = [ | ||
| `session=${sessionId}`, | ||
| `offer=${offer.id}`, | ||
| `step=${step}`, | ||
| `ads=${offer.adsRequired}`, | ||
| ].join("&"); | ||
|
|
||
| return new admob.RewardedAd({ | ||
| adUnitId: rewardedUnitId, | ||
| serverSideVerification: { | ||
| userId, | ||
| customData, | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
sets up server-side verification with custom data, but the client-side redeem() call (line 386) executes immediately after the client-side "reward" event fires, without waiting for server-side verification from Google.
This creates a potential race condition where rewards could be redeemed before Google's servers verify the ad was legitimately watched. A malicious modified app could trigger the reward event without actually displaying ads.
Consider implementing a backend webhook that receives Google's server-side verification callback and gates the secureAdRewardState.redeem() call on that verification.
Uh oh!
There was an error while loading. Please reload this page.