@@ -3,6 +3,8 @@ const express = require('express');
3
3
const cors = require ( 'cors' ) ;
4
4
const sessionsDB = require ( './sessions-db' ) ;
5
5
const subscriptionsDB = require ( './subscriptions-db' ) ;
6
+ const verboseLogger = require ( './verboseLogger' ) ;
7
+ const webhooksDB = require ( './webhooks-db' ) ;
6
8
7
9
const router = express . Router ( ) ;
8
10
router . get ( '/' , ( req , res , next ) => {
@@ -60,7 +62,20 @@ function fetchUser(req, res, next) {
60
62
*/
61
63
router . get ( '/me' , fetchUser , ( req , res , next ) => {
62
64
console . log ( 'GET /me: ' + req . user . username ) ;
63
- res . json ( req . user ) ;
65
+ webhooksDB . getWebhookInfo ( req . user . username , ( err , webhookInfo ) => {
66
+ if ( err ) {
67
+ console . error ( 'Error getting webhook info:' , err ) ;
68
+ webhookInfo = { } ;
69
+ }
70
+ req . user . webhookInfo = webhookInfo ;
71
+ const isWaiting = webhookInfo . wait_start_date && ! webhookInfo . last_webhook_date || webhookInfo . last_webhook_date < webhookInfo . wait_start_date || webhookInfo . last_webhook_date > webhookInfo . wait_end_date ;
72
+ req . user . isWaitingForWebhook = isWaiting ;
73
+ res . set ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, private' ) ;
74
+ res . set ( 'ETag' , Date . now ( ) . toString ( ) ) ;
75
+ res . set ( 'Last-Modified' , new Date ( ) . toUTCString ( ) ) ;
76
+ res . status ( 200 ) ;
77
+ res . json ( req . user ) ;
78
+ } ) ;
64
79
} ) ;
65
80
66
81
/**
@@ -72,30 +87,63 @@ router.post('/webhooks/iaptic', (req, res, next) => {
72
87
const body = req . body ;
73
88
console . log ( 'POST /webhooks/iaptic: ' + JSON . stringify ( body , null , 2 ) ) ;
74
89
if ( body . password !== process . env . IAPTIC_PASSWORD ) {
90
+ console . log ( 'Webhook request rejected: Invalid password' ) ;
75
91
res . status ( 401 ) ;
76
- res . json ( { ok : false } ) ;
92
+ res . json ( { ok : false , error : 'Invalid password' } ) ;
77
93
return ;
78
94
}
79
95
switch ( body . type ) {
80
96
case 'TEST' :
81
97
res . json ( { ok : true , result : 'TEST_PASSED' } ) ;
82
98
break ;
83
99
case 'purchases.updated' :
100
+ if ( ! body . applicationUsername ) {
101
+ console . log ( 'Webhook request missing applicationUsername' ) ;
102
+ res . status ( 200 ) ;
103
+ res . json ( { ok : false , error : 'Missing applicationUsername' } ) ;
104
+ return ;
105
+ }
106
+ // Update the last webhook date for this user
107
+ webhooksDB . updateWebhookInfo ( body . applicationUsername , {
108
+ lastWebhookDate : new Date ( ) . toISOString ( )
109
+ } ) ;
84
110
const lastPurchase = Object . values ( body . purchases ) . reduce ( ( lastPurchase , purchase ) => {
85
111
if ( ! lastPurchase || purchase . expirationDate > lastPurchase . expirationDate ) {
86
112
return purchase ;
87
113
}
88
114
return lastPurchase ;
89
115
} , undefined ) ;
116
+ if ( ! lastPurchase ) {
117
+ console . log ( `Removing subscription for user ${ body . applicationUsername } ` ) ;
118
+ subscriptionsDB . remove ( body . applicationUsername , ( err , wasRemoved ) => {
119
+ res . status ( 200 ) ;
120
+ res . json ( { ok : true , result : wasRemoved ? 'REMOVED' : 'NO_SUBSCRIPTION' } ) ;
121
+ } ) ;
122
+ return ;
123
+ }
124
+ console . log ( `Updating subscription for user ${ body . applicationUsername } ` ) ;
125
+ console . log ( `Last purchase details: ${ JSON . stringify ( lastPurchase , null , 2 ) } ` ) ;
90
126
subscriptionsDB . update ( body . applicationUsername , lastPurchase ) ;
127
+
91
128
res . json ( { ok : true } ) ;
92
129
break ;
93
130
default :
131
+ console . log ( `Webhook request rejected: Unsupported type ${ body . type } ` ) ;
94
132
res . json ( { ok : true , result : 'UNSUPPORTED' } ) ;
95
133
break ;
96
134
}
97
135
} ) ;
98
136
137
+ // Add this new endpoint for initiating webhook wait
138
+ router . post ( '/pending-webhooks' , fetchUser , ( req , res , next ) => {
139
+ const username = req . user . username ;
140
+ const waitStartDate = new Date ( Date . now ( ) - 10 * 1000 ) . toISOString ( ) ; // Assume the webbook might have been sent a few seconds ago already
141
+ const waitEndDate = new Date ( Date . now ( ) + 60 * 60 * 1000 ) . toISOString ( ) ; // Wait for 1 hour
142
+
143
+ webhooksDB . updateWebhookInfo ( username , { waitStartDate, waitEndDate } ) ;
144
+ res . json ( { ok : true , message : 'Webhook wait initiated' } ) ;
145
+ } ) ;
146
+
99
147
/**
100
148
* Access public content.
101
149
*
@@ -119,6 +167,7 @@ router.get('/content/protected/:id', fetchUser, (req, res, next) => {
119
167
const expirationDate = req . user . subscription ? req . user . subscription . expirationDate : undefined ;
120
168
if ( ! expirationDate || expirationDate < new Date ( ) . toISOString ( ) )
121
169
return res . json ( { error : 'NoSubscription' } ) ;
170
+ res . set ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, private' ) ;
122
171
res . json ( {
123
172
title : 'Premium Content' ,
124
173
content : 'This is some information only subscribers can access. 💰' ,
@@ -131,5 +180,6 @@ const app = express();
131
180
app . use ( bodyParser . json ( ) ) ;
132
181
app . use ( bodyParser . urlencoded ( { extended : false } ) ) ;
133
182
app . use ( cors ( ) ) ;
134
- app . use ( process . env . ROUTE_PREFIX || '/demo' , router ) ;
135
- module . exports = app ;
183
+ app . use ( verboseLogger ) ; // Add verbose logger middleware
184
+ app . use ( prefix , router ) ;
185
+ module . exports = app ;
0 commit comments