@unchainedshop/ticketing 3.0.0-rc9 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/express.d.ts +4 -0
- package/lib/express.d.ts.map +1 -0
- package/lib/express.js +17 -0
- package/lib/express.js.map +1 -0
- package/lib/fastify.d.ts +4 -0
- package/lib/fastify.d.ts.map +1 -0
- package/lib/fastify.js +22 -0
- package/lib/fastify.js.map +1 -0
- package/lib/index.d.ts +6 -35
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +8 -19
- package/lib/index.js.map +1 -1
- package/lib/mobile-tickets/apple-handler-express.d.ts +7 -0
- package/lib/mobile-tickets/apple-handler-express.d.ts.map +1 -0
- package/lib/mobile-tickets/{apple-webservice.js → apple-handler-express.js} +3 -9
- package/lib/mobile-tickets/apple-handler-express.js.map +1 -0
- package/lib/mobile-tickets/apple-handler-fastify.d.ts +4 -0
- package/lib/mobile-tickets/apple-handler-fastify.d.ts.map +1 -0
- package/lib/mobile-tickets/apple-handler-fastify.js +158 -0
- package/lib/mobile-tickets/apple-handler-fastify.js.map +1 -0
- package/lib/mobile-tickets/{google-webservice.d.ts → google-handler-express.d.ts} +3 -3
- package/lib/mobile-tickets/google-handler-express.d.ts.map +1 -0
- package/lib/mobile-tickets/{google-webservice.js → google-handler-express.js} +2 -8
- package/lib/mobile-tickets/google-handler-express.js.map +1 -0
- package/lib/mobile-tickets/google-handler-fastify.d.ts +4 -0
- package/lib/mobile-tickets/google-handler-fastify.d.ts.map +1 -0
- package/lib/mobile-tickets/google-handler-fastify.js +41 -0
- package/lib/mobile-tickets/google-handler-fastify.js.map +1 -0
- package/lib/module.d.ts +56 -27
- package/lib/module.d.ts.map +1 -1
- package/lib/module.js +166 -164
- package/lib/module.js.map +1 -1
- package/lib/pdf-tickets/{print-webservice.d.ts → print-handler-express.d.ts} +3 -3
- package/lib/pdf-tickets/print-handler-express.d.ts.map +1 -0
- package/lib/pdf-tickets/{print-webservice.js → print-handler-express.js} +2 -8
- package/lib/pdf-tickets/print-handler-express.js.map +1 -0
- package/lib/pdf-tickets/print-handler-fastify.d.ts +4 -0
- package/lib/pdf-tickets/print-handler-fastify.d.ts.map +1 -0
- package/lib/pdf-tickets/print-handler-fastify.js +24 -0
- package/lib/pdf-tickets/print-handler-fastify.js.map +1 -0
- package/lib/services.d.ts +11 -5
- package/lib/services.d.ts.map +1 -1
- package/lib/services.js +17 -15
- package/lib/services.js.map +1 -1
- package/lib/types.d.ts +1 -3
- package/lib/types.d.ts.map +1 -1
- package/package.json +27 -11
- package/src/express.ts +35 -0
- package/src/fastify.ts +30 -0
- package/src/index.ts +13 -39
- package/src/mobile-tickets/{apple-webservice.ts → apple-handler-express.ts} +3 -16
- package/src/mobile-tickets/apple-handler-fastify.ts +227 -0
- package/src/mobile-tickets/{google-webservice.ts → google-handler-express.ts} +2 -12
- package/src/mobile-tickets/google-handler-fastify.ts +57 -0
- package/src/module.ts +211 -207
- package/src/pdf-tickets/{print-webservice.ts → print-handler-express.ts} +2 -12
- package/src/pdf-tickets/print-handler-fastify.ts +36 -0
- package/src/services.ts +28 -18
- package/src/types.ts +1 -1
- package/lib/mobile-tickets/apple-webservice.d.ts +0 -7
- package/lib/mobile-tickets/apple-webservice.d.ts.map +0 -1
- package/lib/mobile-tickets/apple-webservice.js.map +0 -1
- package/lib/mobile-tickets/google-webservice.d.ts.map +0 -1
- package/lib/mobile-tickets/google-webservice.js.map +0 -1
- package/lib/pdf-tickets/print-webservice.d.ts.map +0 -1
- package/lib/pdf-tickets/print-webservice.js.map +0 -1
package/src/express.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import appleWalletHandler from './mobile-tickets/apple-handler-express.js';
|
|
3
|
+
import googleWalletHandler from './mobile-tickets/google-handler-express.js';
|
|
4
|
+
import printTicketsHandler from './pdf-tickets/print-handler-express.js';
|
|
5
|
+
|
|
6
|
+
export default (app: express.Express) => {
|
|
7
|
+
const {
|
|
8
|
+
APPLE_WALLET_WEBSERVICE_PATH = '/rest/apple-wallet',
|
|
9
|
+
GOOGLE_WALLET_WEBSERVICE_PATH = '/rest/google-wallet',
|
|
10
|
+
UNCHAINED_PDF_PRINT_HANDLER_PATH = '/rest/print_tickets',
|
|
11
|
+
} = process.env;
|
|
12
|
+
|
|
13
|
+
app.use(
|
|
14
|
+
UNCHAINED_PDF_PRINT_HANDLER_PATH,
|
|
15
|
+
express.json({
|
|
16
|
+
type: 'application/json',
|
|
17
|
+
}),
|
|
18
|
+
printTicketsHandler,
|
|
19
|
+
);
|
|
20
|
+
app.use(
|
|
21
|
+
APPLE_WALLET_WEBSERVICE_PATH,
|
|
22
|
+
express.json({
|
|
23
|
+
type: 'application/json',
|
|
24
|
+
}),
|
|
25
|
+
appleWalletHandler,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
app.use(
|
|
29
|
+
GOOGLE_WALLET_WEBSERVICE_PATH,
|
|
30
|
+
express.json({
|
|
31
|
+
type: 'application/json',
|
|
32
|
+
}),
|
|
33
|
+
googleWalletHandler,
|
|
34
|
+
);
|
|
35
|
+
};
|
package/src/fastify.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import appleWalletHandler from './mobile-tickets/apple-handler-fastify.js';
|
|
3
|
+
import googleWalletHandler from './mobile-tickets/google-handler-fastify.js';
|
|
4
|
+
import printTicketsHandler from './pdf-tickets/print-handler-fastify.js';
|
|
5
|
+
|
|
6
|
+
export default (app: FastifyInstance) => {
|
|
7
|
+
const {
|
|
8
|
+
APPLE_WALLET_WEBSERVICE_PATH = '/rest/apple-wallet',
|
|
9
|
+
GOOGLE_WALLET_WEBSERVICE_PATH = '/rest/google-wallet',
|
|
10
|
+
UNCHAINED_PDF_PRINT_HANDLER_PATH = '/rest/print_tickets',
|
|
11
|
+
} = process.env;
|
|
12
|
+
|
|
13
|
+
app.route({
|
|
14
|
+
url: `${APPLE_WALLET_WEBSERVICE_PATH}*`,
|
|
15
|
+
method: ['GET', 'POST', 'DELETE'],
|
|
16
|
+
handler: appleWalletHandler,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
app.route({
|
|
20
|
+
url: `${GOOGLE_WALLET_WEBSERVICE_PATH}/*`,
|
|
21
|
+
method: 'POST',
|
|
22
|
+
handler: googleWalletHandler,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
app.route({
|
|
26
|
+
url: `${UNCHAINED_PDF_PRINT_HANDLER_PATH}/*`,
|
|
27
|
+
method: 'POST',
|
|
28
|
+
handler: printTicketsHandler,
|
|
29
|
+
});
|
|
30
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,59 +1,33 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
1
|
import { subscribe } from '@unchainedshop/events';
|
|
3
2
|
import { RawPayloadType } from '@unchainedshop/events';
|
|
4
3
|
import { WorkerEventTypes, Work } from '@unchainedshop/core-worker';
|
|
5
4
|
import { RendererTypes, registerRenderer } from './template-registry.js';
|
|
6
|
-
import
|
|
7
|
-
import loadGoogleWalletHandler from './mobile-tickets/google-webservice.js';
|
|
8
|
-
import loadPDFHandler from './pdf-tickets/print-webservice.js';
|
|
9
|
-
import passes from './module.js';
|
|
10
|
-
import ticketing from './services.js';
|
|
5
|
+
import ticketingModules, { TicketingModule } from './module.js';
|
|
11
6
|
|
|
12
7
|
import { TicketingAPI } from './types.js';
|
|
13
8
|
import setupMagicKey from './magic-key.js';
|
|
14
|
-
import { TicketingServices } from './services.js';
|
|
9
|
+
import ticketingServices, { TicketingServices } from './services.js';
|
|
15
10
|
|
|
16
11
|
export type { TicketingAPI, RendererTypes };
|
|
17
12
|
|
|
18
|
-
export
|
|
19
|
-
passes,
|
|
20
|
-
};
|
|
13
|
+
export { ticketingServices, ticketingModules, TicketingModule, TicketingServices };
|
|
21
14
|
|
|
22
|
-
export
|
|
23
|
-
ticketing,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export function setupPDFTickets(
|
|
27
|
-
app: express.Express,
|
|
28
|
-
{
|
|
29
|
-
renderOrderPDF,
|
|
30
|
-
}: {
|
|
31
|
-
renderOrderPDF: any;
|
|
32
|
-
},
|
|
33
|
-
) {
|
|
15
|
+
export function setupPDFTickets({ renderOrderPDF }: { renderOrderPDF: any }) {
|
|
34
16
|
registerRenderer(RendererTypes.ORDER_PDF, renderOrderPDF);
|
|
35
|
-
loadPDFHandler(app);
|
|
36
17
|
}
|
|
37
18
|
|
|
38
|
-
export function setupMobileTickets(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
createAppleWalletPass: any;
|
|
46
|
-
},
|
|
47
|
-
) {
|
|
19
|
+
export function setupMobileTickets({
|
|
20
|
+
createGoogleWalletPass,
|
|
21
|
+
createAppleWalletPass,
|
|
22
|
+
}: {
|
|
23
|
+
createGoogleWalletPass: any;
|
|
24
|
+
createAppleWalletPass: any;
|
|
25
|
+
}) {
|
|
48
26
|
registerRenderer(RendererTypes.GOOGLE_WALLET, createGoogleWalletPass);
|
|
49
27
|
registerRenderer(RendererTypes.APPLE_WALLET, createAppleWalletPass);
|
|
50
|
-
|
|
51
|
-
loadAppleWalletHandler(app);
|
|
52
|
-
loadGoogleWalletHandler(app);
|
|
53
28
|
}
|
|
54
29
|
|
|
55
30
|
export default function setupTicketing(
|
|
56
|
-
app: express.Express,
|
|
57
31
|
unchainedAPI: TicketingAPI,
|
|
58
32
|
{
|
|
59
33
|
renderOrderPDF,
|
|
@@ -65,10 +39,10 @@ export default function setupTicketing(
|
|
|
65
39
|
createGoogleWalletPass: any;
|
|
66
40
|
},
|
|
67
41
|
) {
|
|
68
|
-
setupPDFTickets(
|
|
42
|
+
setupPDFTickets({
|
|
69
43
|
renderOrderPDF,
|
|
70
44
|
});
|
|
71
|
-
setupMobileTickets(
|
|
45
|
+
setupMobileTickets({
|
|
72
46
|
createAppleWalletPass,
|
|
73
47
|
createGoogleWalletPass,
|
|
74
48
|
});
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
-
import
|
|
2
|
+
import type { Request, Response } from 'express';
|
|
3
3
|
import { TicketingAPI } from '../types.js';
|
|
4
4
|
import { getFileAdapter } from '@unchainedshop/core-files';
|
|
5
5
|
|
|
6
6
|
const logger = createLogger('unchained:apple-wallet-webservice');
|
|
7
7
|
|
|
8
|
-
const { APPLE_WALLET_WEBSERVICE_PATH = '/rest/apple-wallet' } = process.env;
|
|
9
|
-
|
|
10
8
|
const isAuthenticationTokenCorrect = (req, authenticationToken) => {
|
|
11
9
|
const expectedAuthorizationValue = `ApplePass ${authenticationToken}`;
|
|
12
10
|
return req.headers.authorization === expectedAuthorizationValue;
|
|
13
11
|
};
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
req: Request & { unchainedContext: TicketingAPI },
|
|
17
|
-
res: Response,
|
|
18
|
-
) => {
|
|
13
|
+
const appleWalletHandler = async (req: Request & { unchainedContext: TicketingAPI }, res: Response) => {
|
|
19
14
|
const resolvedContext = req.unchainedContext;
|
|
20
15
|
const { modules } = resolvedContext;
|
|
21
16
|
logger.info(`${req.path} (${JSON.stringify(req.query)})`);
|
|
@@ -239,12 +234,4 @@ export const appleWalletHandler = async (
|
|
|
239
234
|
res.end();
|
|
240
235
|
};
|
|
241
236
|
|
|
242
|
-
export default
|
|
243
|
-
app.use(
|
|
244
|
-
APPLE_WALLET_WEBSERVICE_PATH,
|
|
245
|
-
express.json({
|
|
246
|
-
type: 'application/json',
|
|
247
|
-
}),
|
|
248
|
-
appleWalletHandler,
|
|
249
|
-
);
|
|
250
|
-
}
|
|
237
|
+
export default appleWalletHandler;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
+
import { TicketingAPI } from '../types.js';
|
|
3
|
+
import { getFileAdapter } from '@unchainedshop/core-files';
|
|
4
|
+
import type { FastifyRequest, RouteHandlerMethod } from 'fastify';
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('unchained:apple-wallet-webservice');
|
|
7
|
+
|
|
8
|
+
const isAuthenticationTokenCorrect = (req, authenticationToken) => {
|
|
9
|
+
const expectedAuthorizationValue = `ApplePass ${authenticationToken}`;
|
|
10
|
+
return req.headers.authorization === expectedAuthorizationValue;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const appleWalletHandler: RouteHandlerMethod = async (
|
|
14
|
+
req: FastifyRequest & {
|
|
15
|
+
unchainedContext: TicketingAPI;
|
|
16
|
+
},
|
|
17
|
+
reply,
|
|
18
|
+
) => {
|
|
19
|
+
const resolvedContext = req.unchainedContext;
|
|
20
|
+
const { modules } = resolvedContext;
|
|
21
|
+
|
|
22
|
+
const path = req.url;
|
|
23
|
+
|
|
24
|
+
logger.info(`${path} (${JSON.stringify(req.query)})`);
|
|
25
|
+
|
|
26
|
+
if (path.startsWith('/download/')) {
|
|
27
|
+
try {
|
|
28
|
+
const [, , passFileName] = path.split('/');
|
|
29
|
+
const [tokenId] = passFileName.split('.pkpass');
|
|
30
|
+
|
|
31
|
+
if (!tokenId) {
|
|
32
|
+
reply.status(404);
|
|
33
|
+
return reply.send();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const token = await modules.warehousing.findToken({
|
|
37
|
+
tokenId,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (!token) {
|
|
41
|
+
reply.status(404);
|
|
42
|
+
return reply.send('Token not found');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { hash } = req.query as Record<string, string>;
|
|
46
|
+
const correctHash = await modules.warehousing.buildAccessKeyForToken(tokenId);
|
|
47
|
+
if (hash !== correctHash) {
|
|
48
|
+
reply.status(403);
|
|
49
|
+
return reply.send('Token hash invalid for current owner');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const passFile = await modules.passes.upsertAppleWalletPass(token, resolvedContext);
|
|
53
|
+
|
|
54
|
+
const fileUploadAdapter = getFileAdapter();
|
|
55
|
+
const signedUrl = await fileUploadAdapter.createDownloadURL(passFile);
|
|
56
|
+
const url = signedUrl && (await modules.files.normalizeUrl(signedUrl, {}));
|
|
57
|
+
|
|
58
|
+
const response = await fetch(url);
|
|
59
|
+
const data = await response.arrayBuffer();
|
|
60
|
+
const uint8View = new Uint8Array(data);
|
|
61
|
+
|
|
62
|
+
reply.status(200);
|
|
63
|
+
reply.header('content-type', 'application/vnd.apple.pkpass');
|
|
64
|
+
reply.header('Content-Disposition', `attachment; filename=${tokenId}.pkpass`);
|
|
65
|
+
return reply.send(uint8View);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.error(e);
|
|
68
|
+
}
|
|
69
|
+
reply.status(500);
|
|
70
|
+
return reply.send();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const [, apiVersion, endpoint, ...pathComponents] = path.split("/"); /* eslint-disable-line */
|
|
74
|
+
if (endpoint === 'devices') {
|
|
75
|
+
if (req.method === 'POST') {
|
|
76
|
+
// Register Device
|
|
77
|
+
const [deviceLibraryIdentifier, , passTypeIdentifier, serialNumber] = pathComponents;
|
|
78
|
+
const { pushToken } = req.body as Record<string, any>;
|
|
79
|
+
|
|
80
|
+
const pass = await modules.passes.findAppleWalletPass(passTypeIdentifier, serialNumber);
|
|
81
|
+
|
|
82
|
+
if (pass) {
|
|
83
|
+
if (
|
|
84
|
+
!isAuthenticationTokenCorrect(
|
|
85
|
+
req,
|
|
86
|
+
(pass.meta.rawData as any)._id || (pass.meta.rawData as any).tokenId,
|
|
87
|
+
)
|
|
88
|
+
) {
|
|
89
|
+
reply.status(401);
|
|
90
|
+
return reply.send();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const newRegistration = await modules.passes.registerDeviceForAppleWalletPass(
|
|
94
|
+
passTypeIdentifier,
|
|
95
|
+
serialNumber,
|
|
96
|
+
{
|
|
97
|
+
deviceLibraryIdentifier,
|
|
98
|
+
pushToken,
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
if (!newRegistration) {
|
|
103
|
+
reply.status(200);
|
|
104
|
+
return reply.send();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
reply.status(201);
|
|
108
|
+
return reply.send();
|
|
109
|
+
}
|
|
110
|
+
} else if (req.method === 'GET') {
|
|
111
|
+
// Get the List of Updatable Passes
|
|
112
|
+
const lastUpdated = new Date();
|
|
113
|
+
const [deviceLibraryIdentifier, , passTypeIdentifier] = pathComponents;
|
|
114
|
+
const passesUpdatedSince =
|
|
115
|
+
(req.query as Record<string, string>)?.passesUpdatedSince &&
|
|
116
|
+
new Date((req.query as Record<string, string>).passesUpdatedSince as string);
|
|
117
|
+
|
|
118
|
+
const passes = await modules.passes.findUpdatedAppleWalletPasses(
|
|
119
|
+
passTypeIdentifier,
|
|
120
|
+
deviceLibraryIdentifier,
|
|
121
|
+
passesUpdatedSince,
|
|
122
|
+
);
|
|
123
|
+
const serialNumbers = passes.map((t) => t.meta.serialNumber);
|
|
124
|
+
|
|
125
|
+
if (serialNumbers?.length) {
|
|
126
|
+
reply.status(200);
|
|
127
|
+
reply.header('content-type', 'application/json');
|
|
128
|
+
return reply.send(
|
|
129
|
+
JSON.stringify({
|
|
130
|
+
serialNumbers,
|
|
131
|
+
lastUpdated,
|
|
132
|
+
}),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
reply.status(204);
|
|
137
|
+
return reply.send();
|
|
138
|
+
} else if (req.method === 'DELETE') {
|
|
139
|
+
// Unregister Device
|
|
140
|
+
const [deviceLibraryIdentifier, , passTypeIdentifier, serialNumber] = pathComponents;
|
|
141
|
+
|
|
142
|
+
const pass = await modules.passes.findAppleWalletPass(passTypeIdentifier, serialNumber);
|
|
143
|
+
|
|
144
|
+
if (pass) {
|
|
145
|
+
if (
|
|
146
|
+
!isAuthenticationTokenCorrect(
|
|
147
|
+
req,
|
|
148
|
+
(pass.meta.rawData as any)._id || (pass.meta.rawData as any).tokenId,
|
|
149
|
+
)
|
|
150
|
+
) {
|
|
151
|
+
reply.status(401);
|
|
152
|
+
return reply.send();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await modules.passes.unregisterDeviceForAppleWalletPass(
|
|
156
|
+
passTypeIdentifier,
|
|
157
|
+
serialNumber,
|
|
158
|
+
deviceLibraryIdentifier,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Unregistered
|
|
162
|
+
reply.status(200);
|
|
163
|
+
return reply.send();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} else if (endpoint === 'log') {
|
|
167
|
+
// Log Mesage
|
|
168
|
+
const { logs } = req.body as Record<string, any>;
|
|
169
|
+
logs?.forEach((log) => {
|
|
170
|
+
if (typeof log === 'string') {
|
|
171
|
+
logger.info(log);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
reply.status(200);
|
|
175
|
+
return reply.send();
|
|
176
|
+
} else if (endpoint === 'passes') {
|
|
177
|
+
if (req.method === 'GET') {
|
|
178
|
+
// Get an updated Pass
|
|
179
|
+
const [passTypeIdentifier, serialNumber] = pathComponents;
|
|
180
|
+
|
|
181
|
+
const pass = await modules.passes.findAppleWalletPass(passTypeIdentifier, serialNumber);
|
|
182
|
+
|
|
183
|
+
if (pass) {
|
|
184
|
+
if (
|
|
185
|
+
!isAuthenticationTokenCorrect(
|
|
186
|
+
req,
|
|
187
|
+
(pass.meta.rawData as any)._id || (pass.meta.rawData as any).tokenId,
|
|
188
|
+
)
|
|
189
|
+
) {
|
|
190
|
+
reply.status(401);
|
|
191
|
+
return reply.send();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const { updated, created } = pass;
|
|
195
|
+
|
|
196
|
+
const lastModifiedDate = new Date(updated || created);
|
|
197
|
+
lastModifiedDate.setMilliseconds(0);
|
|
198
|
+
|
|
199
|
+
const ifModifiedSinceDate = new Date(req.headers['if-modified-since']);
|
|
200
|
+
ifModifiedSinceDate.setMilliseconds(0);
|
|
201
|
+
|
|
202
|
+
if (ifModifiedSinceDate.getTime() >= lastModifiedDate.getTime()) {
|
|
203
|
+
reply.status(304);
|
|
204
|
+
return reply.send();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const fileUploadAdapter = getFileAdapter();
|
|
208
|
+
const signedUrl = await fileUploadAdapter.createDownloadURL(pass);
|
|
209
|
+
const url = signedUrl && (await modules.files.normalizeUrl(signedUrl, {}));
|
|
210
|
+
|
|
211
|
+
const result = await fetch(url);
|
|
212
|
+
const data = await result.arrayBuffer();
|
|
213
|
+
const uint8View = new Uint8Array(data);
|
|
214
|
+
|
|
215
|
+
reply.status(200);
|
|
216
|
+
reply.header('content-type', 'application/vnd.apple.pkpass');
|
|
217
|
+
reply.header('last-modified', lastModifiedDate.toUTCString());
|
|
218
|
+
return reply.send(uint8View);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
reply.status(404);
|
|
224
|
+
return reply.send();
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
export default appleWalletHandler;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
-
import
|
|
2
|
+
import type { Request, Response } from 'express';
|
|
3
3
|
import { TicketingAPI } from '../types.js';
|
|
4
4
|
|
|
5
5
|
const logger = createLogger('unchained:google-wallet-webservice');
|
|
6
6
|
|
|
7
|
-
const { GOOGLE_WALLET_WEBSERVICE_PATH = '/rest/google-wallet' } = process.env;
|
|
8
|
-
|
|
9
7
|
export const googleWalletHandler = async (
|
|
10
8
|
req: Request & { unchainedContext: TicketingAPI },
|
|
11
9
|
res: Response,
|
|
@@ -57,12 +55,4 @@ export const googleWalletHandler = async (
|
|
|
57
55
|
res.end();
|
|
58
56
|
};
|
|
59
57
|
|
|
60
|
-
export default
|
|
61
|
-
app.use(
|
|
62
|
-
GOOGLE_WALLET_WEBSERVICE_PATH,
|
|
63
|
-
express.json({
|
|
64
|
-
type: 'application/json',
|
|
65
|
-
}),
|
|
66
|
-
googleWalletHandler,
|
|
67
|
-
);
|
|
68
|
-
}
|
|
58
|
+
export default googleWalletHandler;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
+
import { TicketingAPI } from '../types.js';
|
|
3
|
+
import type { FastifyRequest, RouteHandlerMethod } from 'fastify';
|
|
4
|
+
|
|
5
|
+
const logger = createLogger('unchained:google-wallet-webservice');
|
|
6
|
+
|
|
7
|
+
const googleWalletHandler: RouteHandlerMethod = async (
|
|
8
|
+
req: FastifyRequest & {
|
|
9
|
+
unchainedContext: TicketingAPI;
|
|
10
|
+
},
|
|
11
|
+
reply,
|
|
12
|
+
) => {
|
|
13
|
+
const resolvedContext = req.unchainedContext;
|
|
14
|
+
const { modules } = resolvedContext;
|
|
15
|
+
|
|
16
|
+
const path = req.url;
|
|
17
|
+
|
|
18
|
+
logger.info(`${path} (${JSON.stringify(req.query)})`);
|
|
19
|
+
|
|
20
|
+
if (path.startsWith('/download/')) {
|
|
21
|
+
try {
|
|
22
|
+
const [, , tokenId] = path.split('/');
|
|
23
|
+
|
|
24
|
+
if (!tokenId) {
|
|
25
|
+
reply.status(404);
|
|
26
|
+
return reply.send();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const token = await modules.warehousing.findToken({
|
|
30
|
+
tokenId,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (!token) {
|
|
34
|
+
reply.status(404);
|
|
35
|
+
return reply.send('Token not found');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const { hash } = req.query as Record<string, string>;
|
|
39
|
+
const correctHash = await modules.warehousing.buildAccessKeyForToken(tokenId);
|
|
40
|
+
if (hash !== correctHash) {
|
|
41
|
+
reply.status(403);
|
|
42
|
+
return reply.send('Token hash invalid for current owner');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const pass = await modules.passes.upsertGoogleWalletPass(token, resolvedContext);
|
|
46
|
+
return reply.redirect(await pass.asURL());
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.error(e);
|
|
49
|
+
}
|
|
50
|
+
reply.status(500);
|
|
51
|
+
return reply.send();
|
|
52
|
+
}
|
|
53
|
+
reply.status(404);
|
|
54
|
+
return reply.send();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default googleWalletHandler;
|