Skip to content

Commit b00a5c6

Browse files
fix: trial popping striaght away
1 parent 61aa3ec commit b00a5c6

File tree

8 files changed

+344
-14
lines changed

8 files changed

+344
-14
lines changed

AUTHENTICATION_SETUP.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,44 @@ The authentication flow works seamlessly across all platforms.
136136
3. **Trial timer not working**: Clear localStorage and refresh page
137137
4. **Authentication state not persisting**: Check browser console for errors
138138

139+
### Apple SSO Production Issues
140+
141+
If Apple SSO shows "invalid_request" error in production, check these common causes:
142+
143+
#### 1. **Apple Developer Configuration**
144+
145+
- **Services ID**: Verify your Services ID (`com.ditectrev.education`) is correctly configured in Apple Developer Console
146+
- **Redirect URLs**: Ensure your production domain is added to the "Return URLs" list
147+
- **Domain Verification**: Verify your domain ownership in Apple Developer Console
148+
- **Key Configuration**: Check that your Apple Sign In key is properly configured
149+
150+
#### 2. **Appwrite Configuration**
151+
152+
- **Client ID**: Must match your Apple Services ID exactly (`com.ditectrev.education`)
153+
- **Bundle ID**: Should match your app's bundle identifier
154+
- **Team ID**: Verify this matches your Apple Developer Team ID
155+
- **Key ID**: Must match the Key ID from your Apple Sign In key
156+
- **Private Key**: Ensure the private key is correctly formatted (PEM format)
157+
158+
#### 3. **Production Environment**
159+
160+
- **HTTPS Required**: Apple SSO only works over HTTPS in production
161+
- **Domain Matching**: The domain in the request must match the registered domain
162+
- **Callback URL**: Must be `https://fra.cloud.appwrite.io/v1/account/sessions/oauth2/callback/apple/[PROJECT_ID]`
163+
164+
#### 4. **Debugging Steps**
165+
166+
1. Check Appwrite console logs for detailed error messages
167+
2. Verify all Apple Developer settings match Appwrite configuration
168+
3. Test the OAuth flow manually using Apple's authorization URL
169+
4. Ensure your production domain is verified with Apple
170+
171+
#### 5. **Common Error Codes**
172+
173+
- **invalid_client**: Client ID mismatch or invalid configuration
174+
- **invalid_request**: Malformed request or missing parameters
175+
- **unauthorized_client**: App not authorized for Apple Sign In
176+
139177
### Debug Mode
140178

141179
Enable debug logging by adding to your `.env.local`:

SECURE_TRIAL_SETUP.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ The new system tracks trials **server-side** using:
4040

4141
```text
4242
session_id (string, 255 chars, required)
43+
ip_address (string, 255 chars, required)
4344
user_agent (string, 1000 chars, required)
4445
start_time (integer, required)
4546
end_time (integer, required)
@@ -202,6 +203,7 @@ The code has been updated to use `useSecureTrial` instead of `useTrialTimer`. Th
202203
CREATE TABLE trials (
203204
id VARCHAR(255) PRIMARY KEY,
204205
session_id VARCHAR(255) NOT NULL,
206+
ip_address VARCHAR(255) NOT NULL,
205207
user_agent VARCHAR(1000) NOT NULL,
206208
start_time BIGINT NOT NULL,
207209
end_time BIGINT NOT NULL,

debug-trial.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Simple debug script you can run in browser console
2+
// Copy and paste this into your browser's developer console
3+
4+
console.log("🔍 Debugging trial system in browser...");
5+
6+
// Check if Appwrite is loaded
7+
if (typeof window !== "undefined") {
8+
console.log("✅ Running in browser environment");
9+
10+
// Check environment variables
11+
console.log("Environment check:");
12+
console.log("- Current URL:", window.location.href);
13+
14+
// Check localStorage
15+
console.log("\nLocalStorage check:");
16+
console.log("- currentTrialId:", localStorage.getItem("currentTrialId"));
17+
console.log("- trial_session_id:", localStorage.getItem("trial_session_id"));
18+
console.log("- ip_fallback_id:", localStorage.getItem("ip_fallback_id"));
19+
console.log("- trial_ever_used:", localStorage.getItem("trial_ever_used"));
20+
21+
// Check sessionStorage
22+
console.log("\nSessionStorage check:");
23+
console.log("- trial_ever_used:", sessionStorage.getItem("trial_ever_used"));
24+
25+
// Test Appwrite connection
26+
console.log("\n🧪 Testing Appwrite connection...");
27+
28+
try {
29+
// This will tell us if Appwrite client can be created
30+
fetch("https://fra.cloud.appwrite.io/v1/health")
31+
.then((response) => response.json())
32+
.then((data) => {
33+
console.log("✅ Appwrite server reachable:", data);
34+
})
35+
.catch((error) => {
36+
console.error("❌ Appwrite server not reachable:", error);
37+
});
38+
} catch (error) {
39+
console.error("❌ Failed to test Appwrite connection:", error);
40+
}
41+
} else {
42+
console.log("❌ Not running in browser environment");
43+
}

hooks/useSecureTrial.tsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,20 @@ export const useSecureTrial = () => {
127127
try {
128128
// Check multiple storage mechanisms for trial usage evidence
129129
const localTrialId = localStorage.getItem("currentTrialId");
130-
const sessionId = localStorage.getItem("trial_session_id");
130+
// NOTE: Don't check trial_session_id here - it gets created for new users too!
131131
const fallbackId = localStorage.getItem("ip_fallback_id");
132+
const trialEverUsed = localStorage.getItem("trial_ever_used");
132133

133134
// Also check sessionStorage (survives page refresh but not tab close)
134135
const sessionTrialUsed = sessionStorage.getItem("trial_ever_used");
135136

136137
// If any evidence of previous trial exists, consider it used
137-
return !!(localTrialId || sessionId || fallbackId || sessionTrialUsed);
138+
return !!(
139+
localTrialId ||
140+
fallbackId ||
141+
trialEverUsed ||
142+
sessionTrialUsed
143+
);
138144
} catch (error) {
139145
// If we can't check, assume trial was used (security-first)
140146
return true;
@@ -336,18 +342,7 @@ export const useSecureTrial = () => {
336342
}
337343

338344
try {
339-
// First check if this device has ever used a trial (additional security)
340-
if (hasUsedTrialBefore()) {
341-
// Device has evidence of previous trial usage - block access immediately
342-
setTrialExpired(true);
343-
setTrialBlocked(true);
344-
setTimeRemaining(0);
345-
setTrialStartTime(null);
346-
setIsLoading(false);
347-
return;
348-
}
349-
350-
// Check if user already has an active trial
345+
// First check if user already has an active trial (allow resuming)
351346
const existingTrial = await checkExistingTrial();
352347

353348
if (existingTrial) {

scripts/debug-trial-creation.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* Debug script to test trial creation with browser-like conditions
3+
* Usage: node scripts/debug-trial-creation.js
4+
*/
5+
6+
require("dotenv").config();
7+
const { Client, Databases } = require("node-appwrite");
8+
9+
// Initialize Appwrite client
10+
const client = new Client()
11+
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT)
12+
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)
13+
.setKey(process.env.NEXT_PUBLIC_APPWRITE_API_KEY);
14+
15+
const databases = new Databases(client);
16+
17+
const DATABASE_ID = process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID;
18+
const COLLECTION_ID = process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ID;
19+
20+
async function debugTrialCreation() {
21+
try {
22+
console.log("🔍 Debugging trial creation...");
23+
console.log("=====================================");
24+
console.log(`Database ID: ${DATABASE_ID}`);
25+
console.log(`Collection ID: ${COLLECTION_ID}`);
26+
console.log("");
27+
28+
// Check current state
29+
console.log("1️⃣ Checking current database state...");
30+
const currentTrials = await databases.listDocuments(
31+
DATABASE_ID,
32+
COLLECTION_ID,
33+
);
34+
console.log(`Found ${currentTrials.total} existing trials`);
35+
36+
if (currentTrials.total > 0) {
37+
console.log("Existing trials:");
38+
currentTrials.documents.forEach((trial, index) => {
39+
console.log(` ${index + 1}. ID: ${trial.$id}`);
40+
console.log(` Session: ${trial.session_id}`);
41+
console.log(` IP: ${trial.ip_address}`);
42+
console.log(` Active: ${trial.is_active}`);
43+
console.log(
44+
` Start: ${new Date(trial.start_time).toLocaleString()}`,
45+
);
46+
console.log(` End: ${new Date(trial.end_time).toLocaleString()}`);
47+
console.log("");
48+
});
49+
}
50+
51+
// Simulate browser session creation
52+
console.log("2️⃣ Simulating browser trial creation...");
53+
const sessionId = `browser_session_${Date.now()}_${Math.random()
54+
.toString(36)
55+
.substr(2, 9)}`;
56+
const deviceFingerprint = `fp_browser_${Math.random()
57+
.toString(36)
58+
.substr(2, 9)}`;
59+
const ipAddress = "192.168.1.100"; // Simulate browser IP
60+
const startTime = Date.now();
61+
const endTime = startTime + 15 * 60 * 1000; // 15 minutes
62+
63+
console.log(`Attempting to create trial with:`);
64+
console.log(` Session ID: ${sessionId}`);
65+
console.log(` Device FP: ${deviceFingerprint}`);
66+
console.log(` IP Address: ${ipAddress}`);
67+
console.log(` Start Time: ${new Date(startTime).toLocaleString()}`);
68+
console.log(` End Time: ${new Date(endTime).toLocaleString()}`);
69+
70+
try {
71+
const newTrial = await databases.createDocument(
72+
DATABASE_ID,
73+
COLLECTION_ID,
74+
"unique()",
75+
{
76+
session_id: sessionId,
77+
ip_address: ipAddress,
78+
user_agent:
79+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
80+
start_time: startTime,
81+
end_time: endTime,
82+
is_active: true,
83+
device_fingerprint: deviceFingerprint,
84+
},
85+
);
86+
87+
console.log("✅ Trial creation successful!");
88+
console.log(` New Trial ID: ${newTrial.$id}`);
89+
90+
// Verify it was created
91+
console.log("\n3️⃣ Verifying trial was created...");
92+
const verification = await databases.listDocuments(
93+
DATABASE_ID,
94+
COLLECTION_ID,
95+
);
96+
console.log(`Total trials now: ${verification.total}`);
97+
98+
return newTrial.$id;
99+
} catch (createError) {
100+
console.error("❌ Trial creation failed:", createError.message);
101+
console.error("Error details:", createError);
102+
return null;
103+
}
104+
} catch (error) {
105+
console.error("❌ Debug failed:", error.message);
106+
console.error("Full error:", error);
107+
}
108+
}
109+
110+
debugTrialCreation();

scripts/test-browser-connection.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Test script to check browser-side Appwrite connection
3+
* This simulates what happens in the browser
4+
*/
5+
6+
require("dotenv").config();
7+
8+
// Simulate browser environment variables (these should be NEXT_PUBLIC_*)
9+
const config = {
10+
endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT,
11+
projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID,
12+
databaseId: process.env.NEXT_PUBLIC_APPWRITE_DATABASE_ID,
13+
collectionId: process.env.NEXT_PUBLIC_APPWRITE_COLLECTION_ID,
14+
// Note: Browser doesn't have API key - uses session-based auth
15+
};
16+
17+
console.log("🌐 Testing browser-side configuration...");
18+
console.log("=====================================");
19+
console.log("Environment variables that browser would see:");
20+
console.log(`NEXT_PUBLIC_APPWRITE_ENDPOINT: ${config.endpoint}`);
21+
console.log(`NEXT_PUBLIC_APPWRITE_PROJECT_ID: ${config.projectId}`);
22+
console.log(`NEXT_PUBLIC_APPWRITE_DATABASE_ID: ${config.databaseId}`);
23+
console.log(`NEXT_PUBLIC_APPWRITE_COLLECTION_ID: ${config.collectionId}`);
24+
console.log("");
25+
26+
// Check for missing variables
27+
const missing = [];
28+
if (!config.endpoint) missing.push("NEXT_PUBLIC_APPWRITE_ENDPOINT");
29+
if (!config.projectId) missing.push("NEXT_PUBLIC_APPWRITE_PROJECT_ID");
30+
if (!config.databaseId) missing.push("NEXT_PUBLIC_APPWRITE_DATABASE_ID");
31+
if (!config.collectionId) missing.push("NEXT_PUBLIC_APPWRITE_COLLECTION_ID");
32+
33+
if (missing.length > 0) {
34+
console.error("❌ Missing environment variables:");
35+
missing.forEach((var_name) => console.error(` - ${var_name}`));
36+
console.log("");
37+
console.log("Browser-side code won't work without these variables!");
38+
} else {
39+
console.log("✅ All required environment variables are present");
40+
}
41+
42+
console.log("");
43+
console.log("🔍 Browser limitations to note:");
44+
console.log("- Browser cannot use NEXT_PUBLIC_APPWRITE_API_KEY directly");
45+
console.log("- Browser uses session-based authentication");
46+
console.log("- CORS must be configured in Appwrite console");
47+
console.log("- Network requests may fail if not authenticated");
48+
49+
// Test if we can create a client (without API key like browser would)
50+
try {
51+
const { Client } = require("node-appwrite");
52+
const client = new Client()
53+
.setEndpoint(config.endpoint)
54+
.setProject(config.projectId);
55+
// No .setKey() - browsers don't use API keys
56+
57+
console.log("");
58+
console.log("✅ Client configuration successful (browser-style)");
59+
console.log(
60+
"Note: Actual database operations would require user authentication in browser",
61+
);
62+
} catch (error) {
63+
console.error("❌ Client configuration failed:", error.message);
64+
}

0 commit comments

Comments
 (0)