|
| 1 | +import { waddler } from "waddler/neo"; |
| 2 | +import { S3Client } from "@aws-sdk/client-s3"; |
| 3 | + |
| 4 | +const { NODE_ENV } = process.env; |
| 5 | + |
| 6 | +export const PROD = NODE_ENV === "production"; |
| 7 | +export const NOT_PROD = !PROD; |
| 8 | +export const sql = waddler({ |
| 9 | + url: `md:flight-statii${PROD ? "" : "-dev"}`, |
| 10 | +}); |
| 11 | + |
| 12 | +export const b2 = new S3Client({ |
| 13 | + endpoint: "https://s3.us-west-004.backblazeb2.com", |
| 14 | + region: "us-west-004", |
| 15 | + credentials: { |
| 16 | + accessKeyId: process.env.B2_KEY_ID || "", |
| 17 | + secretAccessKey: process.env.B2_APP_KEY || "", |
| 18 | + }, |
| 19 | +}); |
| 20 | +export const B2_BUCKET = "flybondi-fail"; |
| 21 | +export const B2_PATH = PROD ? "prod" : "dev"; |
| 22 | + |
| 23 | +export const FlightstatsSnapshotEntry = z.object({ |
| 24 | + aerolinea: z.string(), |
| 25 | + vuelo: z.string(), |
| 26 | + aeropuertoIata: z.string(), // origen o destino |
| 27 | + partida: z.string(), |
| 28 | + status: z.string(), |
| 29 | + gate: z.string().optional(), |
| 30 | +}); |
| 31 | +export type FlightstatsSnapshotEntry = z.infer<typeof FlightstatsSnapshotEntry>; |
| 32 | +export const FlightstatsSnapshotEntries = z.array(FlightstatsSnapshotEntry); |
| 33 | +export type FlightstatsSnapshotEntries = z.infer< |
| 34 | + typeof FlightstatsSnapshotEntries |
| 35 | +>; |
| 36 | +export const FlightstatsSnapshot = z.object({ |
| 37 | + url: z.string(), |
| 38 | + fetched_at: z.date(), |
| 39 | + b2_raw_path: z.string(), |
| 40 | + airport_iata: z.string(), |
| 41 | + flights_relative_to_airport: z.enum(["departures", "arrivals"]), |
| 42 | + last_updated_at: z.date().nullable(), |
| 43 | + date: z.date(), |
| 44 | + entries: FlightstatsSnapshotEntries, |
| 45 | +}); |
| 46 | +export type FlightstatsSnapshot = z.infer<typeof FlightstatsSnapshot>; |
| 47 | + |
| 48 | +export const AerolineasSnapshot = z.object({ |
| 49 | + url: z.string(), |
| 50 | + fetched_at: z.date(), |
| 51 | + b2_raw_path: z.string(), |
| 52 | + airport_iata: z.string(), |
| 53 | + flights_relative_to_airport: z.enum(["departures", "arrivals"]), |
| 54 | + date: z.date(), |
| 55 | + entries: z.array(AerolineasFlightData), |
| 56 | +}); |
| 57 | +export type AerolineasSnapshot = z.infer<typeof AerolineasSnapshot>; |
| 58 | + |
| 59 | +// Node no incluye los certificados intermedios y los idiotas de londonsupplygroup no los incluyen los fullchain en su servidor |
| 60 | +// Tenemos que agregarlos manualmente |
| 61 | + |
| 62 | +// https://github.com/fujifish/syswide-cas/blob/master/index.js |
| 63 | +import fs from "fs"; |
| 64 | +import path from "path"; |
| 65 | +import tls from "tls"; |
| 66 | +import { z } from "zod"; |
| 67 | +import { AerolineasFlightData } from "./misc/aerolineas"; |
| 68 | + |
| 69 | +const rootCAs: string[] = []; |
| 70 | + |
| 71 | +function addDefaultCA(file: fs.PathOrFileDescriptor) { |
| 72 | + try { |
| 73 | + var content = fs.readFileSync(file, { encoding: "ascii" }).trim(); |
| 74 | + content = content.replace(/\r\n/g, "\n"); // Handles certificates that have been created in Windows |
| 75 | + var regex = |
| 76 | + /-----BEGIN CERTIFICATE-----\n[\s\S]+?\n-----END CERTIFICATE-----/g; |
| 77 | + var results = content.match(regex); |
| 78 | + if (!results) throw new Error("Could not parse certificate"); |
| 79 | + results.forEach(function (match) { |
| 80 | + rootCAs.push(match.trim()); |
| 81 | + }); |
| 82 | + } catch (e) { |
| 83 | + if (e.code !== "ENOENT") { |
| 84 | + console.log("failed reading file " + file + ": " + e.message); |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +const addCAs = function (dirs: string | string[]) { |
| 90 | + if (!dirs) { |
| 91 | + return; |
| 92 | + } |
| 93 | + |
| 94 | + if (typeof dirs === "string") { |
| 95 | + dirs = dirs.split(",").map(function (dir) { |
| 96 | + return dir.trim(); |
| 97 | + }); |
| 98 | + } |
| 99 | + |
| 100 | + var files, stat, file, i, j; |
| 101 | + for (i = 0; i < dirs.length; ++i) { |
| 102 | + try { |
| 103 | + stat = fs.statSync(dirs[i]); |
| 104 | + if (stat.isDirectory()) { |
| 105 | + files = fs.readdirSync(dirs[i]); |
| 106 | + for (j = 0; j < files.length; ++j) { |
| 107 | + file = path.resolve(dirs[i], files[j]); |
| 108 | + try { |
| 109 | + stat = fs.statSync(file); |
| 110 | + if (stat.isFile()) { |
| 111 | + addDefaultCA(file); |
| 112 | + } |
| 113 | + } catch (e) { |
| 114 | + if (e.code !== "ENOENT") { |
| 115 | + console.log("failed reading " + file + ": " + e.message); |
| 116 | + } |
| 117 | + } |
| 118 | + } |
| 119 | + } else { |
| 120 | + addDefaultCA(dirs[i]); |
| 121 | + } |
| 122 | + } catch (e) { |
| 123 | + if (e.code !== "ENOENT") { |
| 124 | + console.log("failed reading " + dirs[i] + ": " + e.message); |
| 125 | + } |
| 126 | + } |
| 127 | + } |
| 128 | +}; |
| 129 | + |
| 130 | +// trap the createSecureContext method and inject custom root CAs whenever invoked |
| 131 | +const origCreateSecureContext = tls.createSecureContext; |
| 132 | +tls.createSecureContext = function (options) { |
| 133 | + var c = origCreateSecureContext.apply(null, arguments); |
| 134 | + if (!options!.ca && rootCAs.length > 0) { |
| 135 | + rootCAs.forEach(function (ca) { |
| 136 | + // add to the created context our own root CAs |
| 137 | + c.context.addCACert(ca); |
| 138 | + }); |
| 139 | + } |
| 140 | + return c; |
| 141 | +}; |
| 142 | + |
| 143 | +const defaultCALocations = [ |
| 144 | + "/etc/ssl/ca-node.pem", |
| 145 | + "misc/flightstats-londonsupplygroup-com-chain.pem", |
| 146 | +]; |
| 147 | + |
| 148 | +addCAs(defaultCALocations); |
0 commit comments