UNPKG

38.4 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.serverOPDS_browse_v2 = exports.serverOPDS_auth_PATH = exports.serverOPDS_dataUrl_PATH = exports.serverOPDS_browse_v2_PATH = void 0;
4var tslib_1 = require("tslib");
5var crypto = require("crypto");
6var css2json = require("css2json");
7var debug_ = require("debug");
8var DotProp = require("dot-prop");
9var express = require("express");
10var jsonMarkup = require("json-markup");
11var morgan = require("morgan");
12var path = require("path");
13var request = require("request");
14var requestPromise = require("request-promise-native");
15var uuid_1 = require("uuid");
16var serializable_1 = require("r2-lcp-js/dist/es5/src/serializable");
17var opds2_1 = require("r2-opds-js/dist/es5/src/opds/opds2/opds2");
18var opds2_authentication_doc_1 = require("r2-opds-js/dist/es5/src/opds/opds2/opds2-authentication-doc");
19var opds2_publication_1 = require("r2-opds-js/dist/es5/src/opds/opds2/opds2-publication");
20var UrlUtils_1 = require("r2-utils-js/dist/es5/src/_utils/http/UrlUtils");
21var JsonUtils_1 = require("r2-utils-js/dist/es5/src/_utils/JsonUtils");
22var BufferUtils_1 = require("r2-utils-js/dist/es5/src/_utils/stream/BufferUtils");
23var json_schema_validate_1 = require("../utils/json-schema-validate");
24var request_ext_1 = require("./request-ext");
25var server_lcp_lsd_show_1 = require("./server-lcp-lsd-show");
26var server_opds_convert_v1_to_v2_1 = require("./server-opds-convert-v1-to-v2");
27var server_trailing_slash_redirect_1 = require("./server-trailing-slash-redirect");
28var debug = debug_("r2:streamer#http/server-opds-browse-v2");
29exports.serverOPDS_browse_v2_PATH = "/opds-v2-browse";
30exports.serverOPDS_dataUrl_PATH = "/data-url";
31exports.serverOPDS_auth_PATH = "/opds-auth";
32var salt = crypto.randomBytes(16).toString("hex");
33var OPDS_AUTH_ENCRYPTION_KEY_BUFFER = crypto.pbkdf2Sync(uuid_1.v4(), salt, 1000, 32, "sha256");
34var OPDS_AUTH_ENCRYPTION_KEY_HEX = OPDS_AUTH_ENCRYPTION_KEY_BUFFER.toString("hex");
35var AES_BLOCK_SIZE = 16;
36var OPDS_AUTH_ENCRYPTION_IV_BUFFER = Buffer.from(uuid_1.v4()).slice(0, AES_BLOCK_SIZE);
37var OPDS_AUTH_ENCRYPTION_IV_HEX = OPDS_AUTH_ENCRYPTION_IV_BUFFER.toString("hex");
38function serverOPDS_browse_v2(_server, topRouter) {
39 var _this = this;
40 var jsonStyle = "\n.json-markup {\n line-height: 17px;\n font-size: 13px;\n font-family: monospace;\n white-space: pre;\n}\n.json-markup-key {\n font-weight: bold;\n}\n.json-markup-bool {\n color: firebrick;\n}\n.json-markup-string {\n color: green;\n}\n.json-markup-null {\n color: gray;\n}\n.json-markup-number {\n color: blue;\n}\n";
41 var routerOPDS_browse_v2 = express.Router({ strict: false });
42 routerOPDS_browse_v2.use(morgan("combined", { stream: { write: function (msg) { return debug(msg); } } }));
43 routerOPDS_browse_v2.use(server_trailing_slash_redirect_1.trailingSlashRedirect);
44 routerOPDS_browse_v2.get("/", function (_req, res) {
45 var html = "<html><head>";
46 html += "<script type=\"text/javascript\">function encodeURIComponent_RFC3986(str) { " +
47 "return encodeURIComponent(str).replace(/[!'()*]/g, (c) => { " +
48 "return \"%\" + c.charCodeAt(0).toString(16); }); }" +
49 "function go(evt) {" +
50 "if (evt) { evt.preventDefault(); } var url = " +
51 "location.origin +" +
52 (" '" + exports.serverOPDS_browse_v2_PATH + "/' +") +
53 " encodeURIComponent_RFC3986(document.getElementById(\"url\").value);" +
54 "location.href = url;}</script>";
55 html += "</head>";
56 html += "<body><h1>OPDS feed browser</h1>";
57 html += "<form onsubmit=\"go();return false;\">" +
58 "<input type=\"text\" name=\"url\" id=\"url\" size=\"80\">" +
59 "<input type=\"submit\" value=\"Go!\"></form>";
60 html += "</body></html>";
61 res.status(200).send(html);
62 });
63 routerOPDS_browse_v2.param("urlEncoded", function (req, _res, next, value, _name) {
64 req.urlEncoded = value;
65 next();
66 });
67 routerOPDS_browse_v2.get("/:" + request_ext_1._urlEncoded + "(*)", function (req, res) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
68 var reqparams, authResponseJson, authResponseBase64, authResponseStr, authRequestBase64, urlDecoded, isSecureHttp, rootUrl, failure, success, headers, needsStreamingResponse, response, err_1;
69 var _this = this;
70 return tslib_1.__generator(this, function (_a) {
71 switch (_a.label) {
72 case 0:
73 reqparams = req.params;
74 if (!reqparams.urlEncoded) {
75 reqparams.urlEncoded = req.urlEncoded;
76 }
77 authResponseBase64 = req.query.authResponse;
78 if (authResponseBase64) {
79 try {
80 authResponseStr = Buffer.from(authResponseBase64, "base64").toString("utf8");
81 authResponseJson = JSON.parse(authResponseStr);
82 }
83 catch (err) {
84 debug(err);
85 }
86 }
87 authRequestBase64 = req.query.authRequest;
88 urlDecoded = reqparams.urlEncoded;
89 debug(urlDecoded);
90 isSecureHttp = req.secure ||
91 req.protocol === "https" ||
92 req.get("X-Forwarded-Proto") === "https";
93 rootUrl = (isSecureHttp ? "https://" : "http://")
94 + req.headers.host;
95 failure = function (err) {
96 debug(err);
97 res.status(500).send("<html><body><p>Internal Server Error</p><p>"
98 + err + "</p></body></html>");
99 };
100 success = function (response) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
101 var isAuthStatusCode, redirectUrl, isBadStatusCode, responseData, err_2, responseStr, responseJson, isPublication, isAuth, opds2Feed, opds2FeedJson, validationStr, doValidate, jsonSchemasRootpath, jsonSchemasNames, validationErrors, _i, validationErrors_1, err, val, valueStr, title, val, valueStr, title, pubIndex, jsonPubTitlePath, funk, css, jsonPrettyOPDS2, authDoc, authObj, authLink, imageLink, imageUrl, authHtmlForm;
102 return tslib_1.__generator(this, function (_a) {
103 switch (_a.label) {
104 case 0:
105 isAuthStatusCode = response.statusCode === 401;
106 if (isAuthStatusCode &&
107 authRequestBase64 && authResponseJson && authResponseJson.refresh_token) {
108 redirectUrl = rootUrl + req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v2_PATH + "/")) +
109 exports.serverOPDS_auth_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(authRequestBase64) +
110 "?" + request_ext_1._authRefresh + "=" + authResponseJson.refresh_token;
111 debug("REDIRECT: " + req.originalUrl + " ==> " + redirectUrl);
112 res.redirect(301, redirectUrl);
113 return [2];
114 }
115 isBadStatusCode = response.statusCode && (response.statusCode < 200 || response.statusCode >= 300);
116 if (!isAuthStatusCode && isBadStatusCode) {
117 failure("HTTP CODE " + response.statusCode);
118 return [2];
119 }
120 _a.label = 1;
121 case 1:
122 _a.trys.push([1, 3, , 4]);
123 return [4, BufferUtils_1.streamToBufferPromise(response)];
124 case 2:
125 responseData = _a.sent();
126 return [3, 4];
127 case 3:
128 err_2 = _a.sent();
129 debug(err_2);
130 res.status(500).send("<html><body><p>Internal Server Error</p><p>"
131 + err_2 + (isAuthStatusCode ? " (Auth 401)" : "") + "</p></body></html>");
132 return [2];
133 case 4:
134 responseStr = responseData.toString("utf8");
135 responseJson = JSON.parse(responseStr);
136 isPublication = !responseJson.publications &&
137 !responseJson.navigation &&
138 !responseJson.groups &&
139 !responseJson.catalogs &&
140 responseJson.metadata;
141 isAuth = !isPublication && responseJson.authentication;
142 opds2Feed = isPublication ? serializable_1.TaJsonDeserialize(responseJson, opds2_publication_1.OPDSPublication) :
143 (isAuth ? serializable_1.TaJsonDeserialize(responseJson, opds2_authentication_doc_1.OPDSAuthenticationDoc) :
144 serializable_1.TaJsonDeserialize(responseJson, opds2_1.OPDSFeed));
145 opds2FeedJson = serializable_1.TaJsonSerialize(opds2Feed);
146 doValidate = !reqparams.jsonPath || reqparams.jsonPath === "all";
147 if (doValidate) {
148 jsonSchemasRootpath = path.join(process.cwd(), "misc", "json-schema");
149 jsonSchemasNames = [
150 "opds/publication",
151 "opds/acquisition-object",
152 "opds/catalog-entry",
153 "opds/feed-metadata",
154 "opds/properties",
155 "webpub-manifest/publication",
156 "webpub-manifest/contributor-object",
157 "webpub-manifest/contributor",
158 "webpub-manifest/link",
159 "webpub-manifest/metadata",
160 "webpub-manifest/subcollection",
161 "webpub-manifest/properties",
162 "webpub-manifest/subject",
163 "webpub-manifest/subject-object",
164 "webpub-manifest/extensions/epub/metadata",
165 "webpub-manifest/extensions/epub/subcollections",
166 "webpub-manifest/extensions/epub/properties",
167 "webpub-manifest/extensions/presentation/metadata",
168 "webpub-manifest/extensions/presentation/properties",
169 "webpub-manifest/language-map",
170 ];
171 if (isAuth) {
172 jsonSchemasNames.unshift("opds/authentication");
173 }
174 else if (!isPublication) {
175 jsonSchemasNames.unshift("opds/feed");
176 }
177 validationErrors = json_schema_validate_1.jsonSchemaValidate(jsonSchemasRootpath, jsonSchemasNames, opds2FeedJson);
178 if (validationErrors) {
179 validationStr = "";
180 for (_i = 0, validationErrors_1 = validationErrors; _i < validationErrors_1.length; _i++) {
181 err = validationErrors_1[_i];
182 debug("JSON Schema validation FAIL.");
183 debug(err);
184 if (isPublication) {
185 val = DotProp.get(opds2FeedJson, err.jsonPath);
186 valueStr = (typeof val === "string") ?
187 "" + val :
188 ((val instanceof Array || typeof val === "object") ?
189 "" + JSON.stringify(val) :
190 "");
191 debug(valueStr);
192 title = DotProp.get(opds2FeedJson, "metadata.title");
193 debug(title);
194 validationStr +=
195 "\n\"" + title + "\"\n\n" + err.ajvMessage + ": " + valueStr + "\n\n'" + err.ajvDataPath.replace(/^\./, "") + "' (" + err.ajvSchemaPath + ")\n\n";
196 }
197 else {
198 val = DotProp.get(opds2FeedJson, err.jsonPath);
199 valueStr = (typeof val === "string") ?
200 "" + val :
201 ((val instanceof Array || typeof val === "object") ?
202 "" + JSON.stringify(val) :
203 "");
204 debug(valueStr);
205 title = "";
206 pubIndex = "";
207 if (/^publications\.[0-9]+/.test(err.jsonPath)) {
208 jsonPubTitlePath = err.jsonPath.replace(/^(publications\.[0-9]+).*/, "$1.metadata.title");
209 debug(jsonPubTitlePath);
210 title = DotProp.get(opds2FeedJson, jsonPubTitlePath);
211 debug(title);
212 pubIndex = err.jsonPath.replace(/^publications\.([0-9]+).*/, "$1");
213 debug(pubIndex);
214 }
215 validationStr +=
216 "\n___________INDEX___________ #" + pubIndex + " \"" + title + "\"\n\n" + err.ajvMessage + ": " + valueStr + "\n\n'" + err.ajvDataPath.replace(/^\./, "") + "' (" + err.ajvSchemaPath + ")\n\n";
217 }
218 }
219 }
220 }
221 funk = function (obj) {
222 if ((obj.href && typeof obj.href === "string") ||
223 (obj.Href && typeof obj.Href === "string")) {
224 var fullHref = obj.href ? obj.href : obj.Href;
225 var isDataUrl = /^data:/.test(fullHref);
226 var isMailUrl = /^mailto:/.test(fullHref);
227 var notFull = !isDataUrl && !isMailUrl && !UrlUtils_1.isHTTP(fullHref);
228 if (notFull) {
229 fullHref = UrlUtils_1.ensureAbsolute(urlDecoded, fullHref);
230 }
231 if ((obj.type && obj.type.indexOf("opds") >= 0 && obj.type.indexOf("json") >= 0) ||
232 (obj.Type && obj.Type.indexOf("opds") >= 0 && obj.Type.indexOf("json") >= 0)) {
233 obj.__href__ = rootUrl + req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v2_PATH + "/")) +
234 exports.serverOPDS_browse_v2_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(fullHref);
235 if (authRequestBase64 && authResponseBase64) {
236 obj.__href__AUTH = obj.__href__ +
237 "?" +
238 request_ext_1._authResponse + "=" + UrlUtils_1.encodeURIComponent_RFC3986(authResponseBase64) +
239 "&" +
240 request_ext_1._authRequest + "=" + UrlUtils_1.encodeURIComponent_RFC3986(authRequestBase64);
241 }
242 }
243 else if (obj.type === "application/vnd.readium.lcp.license.v1.0+json") {
244 obj.__href__ = rootUrl + req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v2_PATH + "/")) +
245 server_lcp_lsd_show_1.serverLCPLSD_show_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(fullHref);
246 if (authRequestBase64 && authResponseBase64) {
247 obj.__href__AUTH = obj.__href__ +
248 "?" +
249 request_ext_1._authResponse + "=" + UrlUtils_1.encodeURIComponent_RFC3986(authResponseBase64) +
250 "&" +
251 request_ext_1._authRequest + "=" + UrlUtils_1.encodeURIComponent_RFC3986(authRequestBase64);
252 }
253 }
254 else if ((obj.type && obj.type.indexOf("application/atom+xml") >= 0) ||
255 (obj.Type && obj.Type.indexOf("application/atom+xml") >= 0)) {
256 obj.__href__ = rootUrl + req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_browse_v2_PATH + "/")) +
257 server_opds_convert_v1_to_v2_1.serverOPDS_convert_v1_to_v2_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(fullHref);
258 }
259 else if (isDataUrl) {
260 }
261 else if (notFull && !isMailUrl) {
262 obj.__href__ = fullHref;
263 }
264 }
265 };
266 JsonUtils_1.traverseJsonObjects(opds2FeedJson, funk);
267 css = css2json(jsonStyle);
268 jsonPrettyOPDS2 = jsonMarkup(opds2FeedJson, css);
269 jsonPrettyOPDS2 = jsonPrettyOPDS2.replace(/>"data:image\/(.*)"</g, "><a href=\"data:image/$1\" target=\"_BLANK\"><img style=\"max-width: 100px;\" src=\"data:image/$1\"></a><");
270 authDoc = isAuth ? opds2Feed : undefined;
271 authObj = (authDoc && authDoc.Authentication) ? authDoc.Authentication.find(function (auth) {
272 return auth.Type === "http://opds-spec.org/auth/oauth/password";
273 }) : undefined;
274 authLink = authObj ? (authObj.Links && authObj.Links.find(function (link) {
275 return link.Rel && link.Rel.includes("authenticate") && link.TypeLink === "application/json";
276 })) : undefined;
277 imageLink = authDoc ? (authDoc.Links && authDoc.Links.find(function (link) {
278 return link.Rel && link.Rel.includes("logo") && link.TypeLink && link.TypeLink.startsWith("image/");
279 })) : undefined;
280 imageUrl = imageLink ? UrlUtils_1.ensureAbsolute(urlDecoded, imageLink.Href) : undefined;
281 authHtmlForm = !authObj ? "" : "\n<hr>\n<form id=\"authForm\">\n <input type=\"text\" name=\"login\" id=\"login\" size=\"40\">\n <span>" + authObj.Labels.Login + "</span>\n<br><br>\n <input type=\"password\" name=\"password\" id=\"password\" size=\"40\">\n <span>" + authObj.Labels.Password + "</span>\n<br><br>\n <input type=\"submit\" value=\"Authenticate\">\n</form>\n" + (imageUrl ? "<img src=\"" + imageUrl + "\" />" : "") + "\n<script type=\"text/javascript\">\n// document.addEventListener(\"DOMContentLoaded\", (event) => {\n// });\nconst formElement = document.getElementById(\"authForm\");\nformElement.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n doAuth();\n});\nfunction encodeURIComponent_RFC3986(str) {\n return encodeURIComponent(str).replace(/[!'()*]/g, (c) => {\n return \"%\" + c.charCodeAt(0).toString(16);\n });\n}\nfunction encodeFormData(json) {\n if (!json) {\n return \"\";\n }\n return Object.keys(json).map((key) => {\n return encodeURIComponent_RFC3986(key) + \"=\" + (json[key] ? encodeURIComponent_RFC3986(json[key]) : \"_\");\n }).join(\"&\");\n}\nfunction hexStrToArrayBuffer(hexStr) {\n return new Uint8Array(\n hexStr\n .match(/.{1,2}/g)\n .map((byte) => {\n return parseInt(byte, 16);\n })\n );\n}\nfunction doAuth() {\n " + (authLink ? "\n const bodyJson = {\n targetUrl: \"" + urlDecoded + "\",\n authUrl: \"" + authLink.Href + "\",\n grant_type: \"password\",\n username: document.getElementById(\"login\").value,\n password: document.getElementById(\"password\").value\n };\n const bodyStr = JSON.stringify(bodyJson);\n\n const textEncoder = new TextEncoder(\"utf-8\");\n const bodyStrEncoded = textEncoder.encode(bodyStr); // Uint8Array\n\n const keyPromise = window.crypto.subtle.importKey(\n \"raw\",\n hexStrToArrayBuffer(\"" + OPDS_AUTH_ENCRYPTION_KEY_HEX + "\"),\n { \"name\": \"AES-CBC\" },\n false,\n [\"encrypt\", \"decrypt\"]\n );\n keyPromise.then((key) => { // CryptoKey\n\n const iv = hexStrToArrayBuffer(\"" + OPDS_AUTH_ENCRYPTION_IV_HEX + "\");\n const encryptedBodyPromise = window.crypto.subtle.encrypt(\n {\n name: \"AES-CBC\",\n iv\n },\n key,\n bodyStrEncoded\n );\n encryptedBodyPromise.then((encryptedBody) => { // ArrayBuffer\n // const arg = String.fromCharCode.apply(null, new Uint8Array(encryptedBody));\n const arg = new Uint8Array(encryptedBody).reduce((data, byte) => {\n return data + String.fromCharCode(byte);\n }, '');\n const encryptedBodyB64 = window.btoa(arg);\n\n const url = location.origin + \"" + exports.serverOPDS_auth_PATH + "/\" + encodeURIComponent_RFC3986(encryptedBodyB64);\n location.href = url;\n }).catch((err) => {\n console.log(err);\n });\n }).catch((err) => {\n console.log(err);\n });\n\n/* does not work because of HTTP CORS, so we forward to NodeJS fetch/request via the serverOPDS_auth_PATH HTTP route\n window.fetch(\"" + authLink.Href + "\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-url-encoded\",\n \"Accept\": \"application/json\"\n },\n body: encodeFormData(bodyJson)\n })\n .then((response) => {\n const res = JSON.stringify(response, null, 4);\n console.log(res);\n })\n .catch((error) => {\n console.log(error);\n });\n*/\n " :
282 "window.alert(\"no auth link!\");") + "\n}\n</script>";
283 res.status(200).send("<html><body>" +
284 "<h1>OPDS2 JSON " +
285 (isPublication ? "entry" : (isAuth ? "authentication" : "feed")) +
286 " (OPDS2) " + (isAuthStatusCode ? " [HTTP 401]" : "") + "</h1>" +
287 "<h2><a href=\"" + urlDecoded + "\">" + urlDecoded + "</a></h2>" +
288 "<hr>" +
289 "<div style=\"overflow-x: auto;margin:0;padding:0;width:100%;height:auto;\">" +
290 jsonPrettyOPDS2 + "</div>" +
291 (doValidate ? (validationStr ? ("<hr><p><pre>" + validationStr + "</pre></p>") : ("<hr><p>JSON SCHEMA OK.</p>")) : "") +
292 authHtmlForm +
293 "</body></html>");
294 return [2];
295 }
296 });
297 }); };
298 headers = {
299 "Accept": "application/json,application/xml",
300 "Accept-Language": "en-UK,en-US;q=0.7,en;q=0.5",
301 "User-Agent": "READIUM2",
302 };
303 if (authResponseJson && authResponseJson.access_token) {
304 headers.Authorization = "Bearer " + authResponseJson.access_token;
305 }
306 needsStreamingResponse = true;
307 if (!needsStreamingResponse) return [3, 1];
308 request.get({
309 headers: headers,
310 method: "GET",
311 uri: urlDecoded,
312 })
313 .on("response", success)
314 .on("error", failure);
315 return [3, 7];
316 case 1:
317 response = void 0;
318 _a.label = 2;
319 case 2:
320 _a.trys.push([2, 4, , 5]);
321 return [4, requestPromise({
322 headers: headers,
323 method: "GET",
324 resolveWithFullResponse: true,
325 uri: urlDecoded,
326 })];
327 case 3:
328 response = _a.sent();
329 return [3, 5];
330 case 4:
331 err_1 = _a.sent();
332 failure(err_1);
333 return [2];
334 case 5: return [4, success(response)];
335 case 6:
336 _a.sent();
337 _a.label = 7;
338 case 7: return [2];
339 }
340 });
341 }); });
342 topRouter.use(exports.serverOPDS_browse_v2_PATH, routerOPDS_browse_v2);
343 var routerOPDS_auth = express.Router({ strict: false });
344 routerOPDS_auth.use(morgan("combined", { stream: { write: function (msg) { return debug(msg); } } }));
345 routerOPDS_auth.use(server_trailing_slash_redirect_1.trailingSlashRedirect);
346 routerOPDS_auth.get("/", function (_req, res) {
347 var html = "<html><body><h1>NOPE</h1></body></html>";
348 res.status(200).send(html);
349 });
350 routerOPDS_auth.param("urlEncoded", function (req, _res, next, value, _name) {
351 req.urlEncoded = value;
352 next();
353 });
354 routerOPDS_auth.get("/:" + request_ext_1._urlEncoded + "(*)", function (req, res) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
355 var reqparams, base64Payload, refreshToken, isSecureHttp, rootUrl, encrypted, decrypteds, decryptStream, buff1, buff2, decrypted, nPaddingBytes, size, decryptedStr, decryptedJson_1, authUrl, targetUrl_1, failure_1, success, headers, needsStreamingResponse, response, err_3, err_4;
356 var _this = this;
357 return tslib_1.__generator(this, function (_a) {
358 switch (_a.label) {
359 case 0:
360 reqparams = req.params;
361 if (!reqparams.urlEncoded) {
362 reqparams.urlEncoded = req.urlEncoded;
363 }
364 base64Payload = reqparams.urlEncoded;
365 refreshToken = req.query.authRefresh;
366 isSecureHttp = req.secure ||
367 req.protocol === "https" ||
368 req.get("X-Forwarded-Proto") === "https";
369 rootUrl = (isSecureHttp ? "https://" : "http://")
370 + req.headers.host;
371 _a.label = 1;
372 case 1:
373 _a.trys.push([1, 9, , 10]);
374 encrypted = Buffer.from(base64Payload, "base64");
375 decrypteds = [];
376 decryptStream = crypto.createDecipheriv("aes-256-cbc", OPDS_AUTH_ENCRYPTION_KEY_BUFFER, OPDS_AUTH_ENCRYPTION_IV_BUFFER);
377 decryptStream.setAutoPadding(false);
378 buff1 = decryptStream.update(encrypted);
379 if (buff1) {
380 decrypteds.push(buff1);
381 }
382 buff2 = decryptStream.final();
383 if (buff2) {
384 decrypteds.push(buff2);
385 }
386 decrypted = Buffer.concat(decrypteds);
387 nPaddingBytes = decrypted[decrypted.length - 1];
388 size = encrypted.length - nPaddingBytes;
389 decryptedStr = decrypted.slice(0, size).toString("utf8");
390 decryptedJson_1 = JSON.parse(decryptedStr);
391 authUrl = decryptedJson_1.authUrl;
392 delete decryptedJson_1.authUrl;
393 targetUrl_1 = decryptedJson_1.targetUrl;
394 delete decryptedJson_1.targetUrl;
395 if (refreshToken) {
396 decryptedJson_1.grant_type = "refresh_token";
397 decryptedJson_1.refresh_token = refreshToken;
398 }
399 failure_1 = function (err) {
400 debug(err);
401 res.status(500).send("<html><body><p>Internal Server Error</p><p>"
402 + err + "</p></body></html>");
403 };
404 success = function (response) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
405 var responseData, err_5, responseStr, responseJson, targetUrl_, refreshTokenUrl;
406 return tslib_1.__generator(this, function (_a) {
407 switch (_a.label) {
408 case 0:
409 if (response.statusCode && (response.statusCode < 200 || response.statusCode >= 300)) {
410 failure_1("HTTP CODE " + response.statusCode);
411 return [2];
412 }
413 _a.label = 1;
414 case 1:
415 _a.trys.push([1, 3, , 4]);
416 return [4, BufferUtils_1.streamToBufferPromise(response)];
417 case 2:
418 responseData = _a.sent();
419 return [3, 4];
420 case 3:
421 err_5 = _a.sent();
422 debug(err_5);
423 res.status(500).send("<html><body><p>Internal Server Error</p><p>"
424 + err_5 + "</p></body></html>");
425 return [2];
426 case 4:
427 try {
428 responseStr = responseData.toString("utf8");
429 responseJson = JSON.parse(responseStr);
430 targetUrl_ = rootUrl + req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_auth_PATH + "/")) +
431 exports.serverOPDS_browse_v2_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(targetUrl_1) +
432 "?" + request_ext_1._authResponse + "=" +
433 UrlUtils_1.encodeURIComponent_RFC3986(Buffer.from(JSON.stringify(responseJson)).toString("base64")) +
434 "&" + request_ext_1._authRequest + "=" + UrlUtils_1.encodeURIComponent_RFC3986(base64Payload);
435 refreshTokenUrl = responseJson.refresh_token ? rootUrl + req.originalUrl.substr(0, req.originalUrl.indexOf(exports.serverOPDS_auth_PATH + "/")) +
436 exports.serverOPDS_auth_PATH + "/" + UrlUtils_1.encodeURIComponent_RFC3986(base64Payload) +
437 "?" + request_ext_1._authRefresh + "=" + UrlUtils_1.encodeURIComponent_RFC3986(responseJson.refresh_token) : undefined;
438 decryptedJson_1.password = "***";
439 res.status(200).send("\n <html><body>\n <hr>\n <a href=\"" + targetUrl_ + "\">" + targetUrl_1 + "</a>\n <hr>\n <pre>" + JSON.stringify(decryptedJson_1, null, 4) + "</pre>\n <hr>\n <pre>" + JSON.stringify(responseJson, null, 4) + "</pre>\n <hr>\n " + (refreshTokenUrl ? "<a href=\"" + refreshTokenUrl + "\">FORCE REFRESH TOKEN</a>" : "") + "\n <hr>\n </body></html>\n ");
440 }
441 catch (err) {
442 debug(err);
443 res.status(500).send("<html><body><p>Internal Server Error</p><p>"
444 + err + "</p></body></html>");
445 return [2];
446 }
447 return [2];
448 }
449 });
450 }); };
451 headers = {
452 "Accept": "application/json,application/xml",
453 "Accept-Language": "en-UK,en-US;q=0.7,en;q=0.5",
454 "Content-Type": "application/x-www-form-url-encoded",
455 "User-Agent": "READIUM2",
456 };
457 needsStreamingResponse = true;
458 if (!needsStreamingResponse) return [3, 2];
459 request.post({
460 form: decryptedJson_1,
461 headers: headers,
462 method: "POST",
463 uri: authUrl,
464 })
465 .on("response", success)
466 .on("error", failure_1);
467 return [3, 8];
468 case 2:
469 response = void 0;
470 _a.label = 3;
471 case 3:
472 _a.trys.push([3, 5, , 6]);
473 return [4, requestPromise({
474 form: decryptedJson_1,
475 headers: headers,
476 method: "POST",
477 resolveWithFullResponse: true,
478 uri: authUrl,
479 })];
480 case 4:
481 response = _a.sent();
482 return [3, 6];
483 case 5:
484 err_3 = _a.sent();
485 failure_1(err_3);
486 return [2];
487 case 6: return [4, success(response)];
488 case 7:
489 _a.sent();
490 _a.label = 8;
491 case 8: return [3, 10];
492 case 9:
493 err_4 = _a.sent();
494 debug(err_4);
495 res.status(500).send("<html><body><p>Internal Server Error</p><p>"
496 + "--" + "</p></body></html>");
497 return [3, 10];
498 case 10: return [2];
499 }
500 });
501 }); });
502 topRouter.use(exports.serverOPDS_auth_PATH, routerOPDS_auth);
503}
504exports.serverOPDS_browse_v2 = serverOPDS_browse_v2;
505//# sourceMappingURL=server-opds-browse-v2.js.map
\No newline at end of file