From 9337f736f0bb5f30fb988f783bd214d6816509cc Mon Sep 17 00:00:00 2001 From: jpsl Date: Tue, 18 Oct 2022 19:41:03 +0100 Subject: [PATCH 1/9] #119 - ship and sell all DFM products --- bin/environment/wsCreateStuff.js | 142 +++++++++++++++++-------------- 1 file changed, 76 insertions(+), 66 deletions(-) diff --git a/bin/environment/wsCreateStuff.js b/bin/environment/wsCreateStuff.js index f22a8ef3..7185f94a 100644 --- a/bin/environment/wsCreateStuff.js +++ b/bin/environment/wsCreateStuff.js @@ -1,7 +1,7 @@ /** * Experimental tool to create some products and batches using api services. * Uses some files common to the setup.js utility, - * #66 + * #66, #119 * * Onde node <= v14 we recommend that you run this script with option * --unhandled-rejections=strict @@ -49,7 +49,7 @@ const WSH1 = require("../../docker/api/env/whs-1.json"); const WSH2 = require("../../docker/api/env/whs-2.json"); const PHA1 = require("../../docker/api/env/pha-1.json"); const PHA2 = require("../../docker/api/env/pha-2.json"); -const SHIPMENTS_ON_PHA = []; +const SHIPMENTS_ON_PHA = []; // records all shipments sent to a PHA, so that they can be sold. const NUM_SALES = 2; // number of sales to perform - for now consume serialNumbers from 1st MSD batch const MY_SALES = []; // array of data returned by /sale/create @@ -607,40 +607,45 @@ const shipmentsCreateTestDfm = async function (conf, sender) { const whs = WSH1; const pha = PHA1; - - const gtin1 = sender.products[0].gtin; - const batch1 = sender.batches[gtin1][0]; - const batchNumber1 = batch1.batchNumber; - const quantity1 = batch1.quantity; - const shipment1MahToWhs = { - "orderId": whs.id.secret + "-" + (new Date()).toISOString(), - "requesterId": whs.id.secret, - "shipmentLines": [ - { - "gtin": gtin1, - "batch": batchNumber1, - "quantity": quantity1 + for (const product of sender.products) { // ship all DFM products + const gtin = product.gtin; + for (const batch of sender.batches[gtin]) { // ship all DFM batches + const batchNumber = batch.batchNumber; + const quantity = batch.quantity; + + const shipment1MahToWhs = { + "orderId": whs.id.secret + "-" + (new Date()).toISOString(), + "requesterId": whs.id.secret, + "shipmentLines": [ + { + "gtin": gtin, + "batch": batchNumber, + "quantity": quantity + } } - ] - }; - - await shipmentCreateAndDeliver(conf, sender, whs, shipment1MahToWhs); - - const shipment2WhsToPha = { - "orderId": pha.id.secret + "-" + (new Date()).toISOString(), - "requesterId": pha.id.secret, - "shipmentLines": [ - { - "gtin": gtin1, - "batch": batchNumber1, - "quantity": quantity1 - } - ] - }; + } + ] + }; + + await shipmentCreateAndDeliver(conf, sender, whs, shipment1MahToWhs); + + const shipment2WhsToPha = { + "orderId": pha.id.secret + "-" + (new Date()).toISOString(), + "requesterId": pha.id.secret, + "shipmentLines": [ + { + "gtin": gtin, + "batch": batchNumber, + "quantity": quantity + } + ] + }; - const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); - SHIPMENTS_ON_PHA.push(resShipToPha); + const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); + SHIPMENTS_ON_PHA.push(resShipToPha); + } + } } const shipmentsCreateTestDefault = async function (conf, sender) { @@ -794,42 +799,47 @@ const salesCreateTestDfm = async function (conf, manufActor, sellerActor, mySale if (!SHIPMENTS_ON_PHA.length) { throw new Error("No shipments on pharmacies on this run!"); } - if (!SHIPMENTS_ON_PHA[0].shipmentLines.length) { - throw new Error("No shipmentLines on pharmacies on this run!"); - } - const shipmentLine0 = SHIPMENTS_ON_PHA[0].shipmentLines[0]; - const gtin = shipmentLine0.gtin; - const batchNumber = shipmentLine0.batch; - const batch = findMahOriginalBatch(gtin, batchNumber); - //console.log("batch", batch); - - let i=0; - while (i Date: Tue, 18 Oct 2022 19:44:53 +0100 Subject: [PATCH 2/9] #66 - update timing comments --- bin/environment/wsCreateStuff.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/environment/wsCreateStuff.js b/bin/environment/wsCreateStuff.js index 7185f94a..af6d9fa5 100644 --- a/bin/environment/wsCreateStuff.js +++ b/bin/environment/wsCreateStuff.js @@ -12,10 +12,10 @@ * See --help for options. * * Please add a --sleep=NNNNN (default is 2000 miliseconds = 2 seconds) - * between shipment operations to allow for messages betweem participants to be processed. - * At least 10 seconds seems to be required. + * between shipment operations to allow for messages between participants to be processed. + * At least 10 seconds seems to be required for simulated blockchain. * For BC --istanbul.blockperiod 1 (1 second per new block) this timing needs to - * be 80 seconds (80000 ms) or more. + * be 120 seconds (120000 ms) or more. * * Example for the top README.md scenario - running single MAH (defaults to ROCHE credentials) API on localhost:8081 : * fgt-workspace/bin/environment$ node --unhandled-rejections=strict wsCreateStuff.js --env=single --scenario=single --sleep=80000 2>&1 | tee -a wsCreateStuffSingle.log From 4a59c35a4dc6ece2647be89b761c7688c8b278d2 Mon Sep 17 00:00:00 2001 From: jpsl Date: Tue, 18 Oct 2022 19:55:36 +0100 Subject: [PATCH 3/9] #119 - removed duplicated batch WB5208 --- bin/environment/batches/batchesTests.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/bin/environment/batches/batchesTests.js b/bin/environment/batches/batchesTests.js index 79fc4fed..ea547e20 100644 --- a/bin/environment/batches/batchesTests.js +++ b/bin/environment/batches/batchesTests.js @@ -418,14 +418,6 @@ const DFM_BATCHES1 = { 'ZJ1459SC1' ] }, - { - batchNumber: "WB5208", - quantity: 1, - expiry: "2030/12/31", - serialNumbers: [ - 'VQ8911LQ7' - ] - }, { batchNumber: "WO6983", quantity: 1, From 29d527d52b5540d03509e1a25722a573fdaee270 Mon Sep 17 00:00:00 2001 From: jpsl Date: Tue, 18 Oct 2022 20:01:51 +0100 Subject: [PATCH 4/9] #119 - bad brace fix --- bin/environment/wsCreateStuff.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/environment/wsCreateStuff.js b/bin/environment/wsCreateStuff.js index af6d9fa5..42c12465 100644 --- a/bin/environment/wsCreateStuff.js +++ b/bin/environment/wsCreateStuff.js @@ -623,8 +623,6 @@ const shipmentsCreateTestDfm = async function (conf, sender) { "batch": batchNumber, "quantity": quantity } - } - } ] }; From 018c646623a1c1c4606c26aa291f3b8ff27225c4 Mon Sep 17 00:00:00 2001 From: jpsl Date: Tue, 18 Oct 2022 21:06:52 +0100 Subject: [PATCH 5/9] #119 - fix shipmentLines.length check --- bin/environment/wsCreateStuff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/environment/wsCreateStuff.js b/bin/environment/wsCreateStuff.js index 42c12465..1f09df4e 100644 --- a/bin/environment/wsCreateStuff.js +++ b/bin/environment/wsCreateStuff.js @@ -798,7 +798,7 @@ const salesCreateTestDfm = async function (conf, manufActor, sellerActor, mySale throw new Error("No shipments on pharmacies on this run!"); } for (const shipment of SHIPMENTS_ON_PHA) { - if (shipment.shipmentLines.length) { + if (!shipment.shipmentLines.length) { throw new Error("No shipmentLines on pharmacies on this run!"); } if (shipment.shipmentLines.length != 1) { From adb1ced534329334708d441aa83c77512ae87d60 Mon Sep 17 00:00:00 2001 From: jpsl Date: Wed, 19 Oct 2022 11:07:18 +0100 Subject: [PATCH 6/9] #119 - handle lack of disk space https://github.com/PharmaLedger-IMI/fgt-workspace/issues/119#issuecomment-1283748884 --- bin/environment/wsCreateStuffDfm2.js | 1015 ++++++++++++++++++++++++++ 1 file changed, 1015 insertions(+) create mode 100644 bin/environment/wsCreateStuffDfm2.js diff --git a/bin/environment/wsCreateStuffDfm2.js b/bin/environment/wsCreateStuffDfm2.js new file mode 100644 index 00000000..dc6176f8 --- /dev/null +++ b/bin/environment/wsCreateStuffDfm2.js @@ -0,0 +1,1015 @@ +/** + * Fork of wsCreateStuff.js for a specific DFM situation: + * https://github.com/PharmaLedger-IMI/fgt-workspace/issues/119#issuecomment-1283748884 + * + * Delete it, if you do not know what you would need it for... :-) + * + */ + +const http = require('http'); +const https = require('https'); + +const { argParser, validateGtin, generateRandomInt } = require('./utils'); +const { encodeBase64 } = require('../../fgt-api/utils/basicAuth'); + +const ShipmentStatus = require('../../fgt-dsu-wizard/model/ShipmentStatus'); +const BatchStatus = require('../../fgt-dsu-wizard/model/BatchStatus'); + +const credentials = require('./credentials/credentialsTests'); // TODO require ../../docker/api/env/mah-*.json ? +const MAHS = [credentials.PFIZER, credentials.MSD, credentials.ROCHE, credentials.BAYER, credentials.NOVO_NORDISK, credentials.GSK, credentials.TAKEDA, credentials.SANOFI]; +const MAH_MSD = credentials.MSD; +// #106 test one participant with credentials overridden by environment on docker-compose.yml +// MAH_MSD.id.secret="MAH0000000"; +const MAH_ROCHE = credentials.ROCHE; +// #106 test one participant with credentials overridden by environment on docker-compose.yml +// MAH_ROCHE.id.secret="MAH0000000"; +const MAH_BAYER = credentials.BAYER; +const WSH1 = require("../../docker/api/env/whs-1.json"); +const WSH2 = require("../../docker/api/env/whs-2.json"); +const PHA1 = require("../../docker/api/env/pha-1.json"); +const PHA2 = require("../../docker/api/env/pha-2.json"); +const SHIPMENTS_ON_PHA = []; // records all shipments sent to a PHA, so that they can be sold. + +const NUM_SALES = 2; // number of sales to perform - for now consume serialNumbers from 1st MSD batch +const MY_SALES = []; // array of data returned by /sale/create + +let SLEEP_MS = 2000; + +const PRODUCTS_TEST = require('./products/productsTests'); +const BATCHES_TEST = require('./batches/batchesTests'); +const BATCHES_RANDOM = require('./batches/batchesRandom'); + + + +class ProductsEnum { + static none = "none"; + static test = "test"; +}; + +class BatchesEnum { + static none = "none"; + static test = "test"; + static random = "random"; +}; + +class ShipmentsEnum { + static none = "none"; + static test = "test"; + static random = "random"; +}; + +class SalesEnum { + static none = "none"; + static test = "test"; +}; + +class TraceabilityEnum { + static none = "none"; + static test = "test"; +}; + +class ReceiptsEnum { + static none = "none"; + static test = "test"; +}; + +class ScenarioEnum { + static single = "single"; + static default = "default"; + static dfm = "dfm"; // dfm is acdc + static dfm2 = "dfm2"; // dfm is acdc +}; + +function genShipmentId(simpleShipment, identityId) { + let shipmentId; + const splitShipmentId = `${simpleShipment.shipmentId}`.split('-'); + if (identityId === simpleShipment.senderId) { + if (splitShipmentId.length >= 2) + shipmentId = splitShipmentId[splitShipmentId.length - 1]; + else + shipmentId = simpleShipment.shipmentId; + } else { + if (splitShipmentId.length >= 2) + shipmentId = simpleShipment.shipmentId; + else + shipmentId = `${simpleShipment.senderId}-${simpleShipment.shipmentId}`; + } + return shipmentId; +} + +const defaultOps = { + ignoreDups: "t", // falsy will + wsProtocol: "http", + wsDomainSuffix: ".localhost", + wsPortNumber: "8080", + env: "localhost", + products: ProductsEnum.test, + batches: BatchesEnum.test, + shipments: ShipmentsEnum.test, + sales: SalesEnum.test, + traceability: TraceabilityEnum.test, + receipts: ReceiptsEnum.test, + scenario: ScenarioEnum.default, + sleep: "2000" +} + +if (process.argv.includes("--help") + || process.argv.includes("-h") + || process.argv.includes("-?") +) { + console.log("Usage:"); + console.log(); + console.log("\tnode --unhandled-rejections=strict wsCreateStuff.js [options]"); + console.log(); + console.log("Where options can be any of:"); + console.log(); + console.log("\t--env=single|localhost*|dev|tst single is for a single MAH on port 8081"); + console.log("\t--ignoreDups=t*| only for product and batch creation"); + console.log("\t--sleep=2000 number of ms to sleep between API REST calls"); + console.log(); + console.log("\t--batches=none|test*|random"); + console.log("\t--products=none|test*"); + console.log("\t--shipments=none|test*|random"); + console.log("\t--sales=none|test*"); + console.log("\t--receipts=none|test*"); + console.log("\t--traceability=none|test*"); + console.log(); + console.log("\t--scenario=single|default*|dfm The single scenario only creates products and batches"); + console.log("\t\tfor a single specifc MAH. The default scenario will create products, batches,"); + console.log("\t\tshipments, sales, receipts, more shipments, more sales, more receipts,"); + console.log("\t\tthen quarantine one batch, and then recall one batch. The dfm scenario"); + console.log("\t\tcreates some specific producs, batches, shipments and sales for a DFM demo."); + console.log(); + console.log("* - is the default setting"); + process.exit(0); +} + +const conf = argParser(defaultOps, process.argv); + +if (conf.env === "single") { + conf.wsPortNumber = "8081"; +} else if (conf.env === "dev") { + conf.wsDomainSuffix = "-fgt-dev.pharmaledger.pdmfc.com"; + conf.wsPortNumber = "443"; + conf.wsProtocol = "https"; +} else if (conf.env === "tst") { + conf.wsDomainSuffix = "-fgt.pharmaledger.pdmfc.com"; + conf.wsPortNumber = "443"; + conf.wsProtocol = "https"; +} + +if (conf.sleep) { + SLEEP_MS = parseInt(conf.sleep); +} + +/** + * + * Functions + */ + +// Based on +// https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep +function sleep(millis) { + console.log("Sleep "+millis+"ms"); + return new Promise(resolve => setTimeout(resolve, millis)); +} + +// Based on +// https://stackoverflow.com/questions/6158933/how-is-an-http-post-request-made-in-node-js +const jsonHttpRequest = function (conf, actor, { body, ...options }) { + const bodyToSend = (body && typeof body != "string") ? JSON.stringify(body) : body; + + if (!options.headers) { + options.headers = { + 'content-type': 'application/json', + }; + } else if (!options.headers['content-type']) { + options.headers['content-type'] = 'application/json'; + } + if (bodyToSend) + options.headers['content-length'] = Buffer.byteLength(bodyToSend); + if (!options['hostname']) + options.hostname = getHostnameForActor(conf, actor); + if (!options['port']) + options.port = conf.wsPortNumber; + if (!options.headers['Authorization']) { + const secret = `${actor.id.secret}:${(actor.pass.secret)}`; + options.headers['Authorization'] = `Basic ${encodeBase64(secret)}`; + } + + + const beforeReq = new Date(); + const protocol = conf.wsProtocol; + let p = new Promise((resolve, reject) => { + // debug request + console.log((new Date()).toISOString()+": "+protocol+" "+options.method, JSON.stringify(options), bodyToSend); + + const req = (protocol === "http" ? http : https).request( + { + ...options, + }, + res => { + const chunks = []; + res.on('data', data => chunks.push(data)); + res.on('end', () => { + let resBody = Buffer.concat(chunks); + //console.log("res.headers=", res.headers); + const contentType = res.headers['content-type']; + if (contentType && contentType.startsWith('application/json')) { + resolve(JSON.parse(resBody.toString())); // seems to be a JSON reply. Attempt to parse. + } else if (contentType && contentType.startsWith('text/')) { + resolve(resBody.toString()); // seems to be readable text. + } else { + resolve(resBody); // don't know what content-type is this. Return it as a Buffer. + } + }); + } + ); + req.on('error', reject); + if (bodyToSend) { + req.write(bodyToSend); + } + req.end(); + }); + + // debug reply + p.then((r) => { + const afterRes = new Date(); + const ellapsed = afterRes.getTime()-beforeReq.getTime(); + console.log(`res ${ellapsed}ms`, r); + }); + + return p; +} + +const jsonGet = function (conf, actor, { body, ...options }) { + options.method = "GET"; + return jsonHttpRequest(conf, actor, { body, ...options }); +} + +const jsonPost = function (conf, actor, { body, ...options }) { + options.method = "POST"; + return jsonHttpRequest(conf, actor, { body, ...options }); +} + +const jsonPut = function (conf, actor, { body, ...options }) { + options.method = "PUT"; + return jsonHttpRequest(conf, actor, { body, ...options }); +} + +const getHostnameForActor = function (conf, actor) { + if (conf.env=="single") { + return "localhost"; + } + // test MAH + let mahMatch = actor.email.secret.match(/^(.*)@mah.*$/); + if (mahMatch) { + let mahName = mahMatch[1].replace(".", "-"); + // special case merck->msd + if (mahName === "merck") + mahName = "msd"; + return `api-mah-${mahName}${conf.wsDomainSuffix}`; + } + // test WHS + let whsMatch = actor.id.secret.match(/^WHS([0-9]+)$/); + if (whsMatch) { + let whsNumber = parseInt(whsMatch[1])+""; // eliminate leading zeros + // taked is special + if (whsNumber==="999999") + whsNumber = "takeda"; + return `api-whs${whsNumber}${conf.wsDomainSuffix}`; + } + // test PHA + let phaMatch = actor.id.secret.match(/^PHA([0-9]+)$/); + if (phaMatch) { + let phaNumber = parseInt(phaMatch[1])+""; // eliminate leading zeros + return `api-pha${phaNumber}${conf.wsDomainSuffix}`; + } + throw new Error("Cannot determine hostname for actor.email=" + actor.email.secret); + //return undefined; +} + +const findMahOriginalBatch = function (gtin, batchNumber) { + //for(const mah of [MAH_MSD]) { // only MSD has good prod+batches + for(const mah of MAHS) { + const batches = mah.batches; + //console.log("Lookging for "+gtin+" "+batchNumber+" in", batches); + if (!batches) continue; + if (gtin in batches) { + const aBatchArray = batches[gtin]; + for (const batch of aBatchArray) { + if (batchNumber == batch.batchNumber) + return batch; + } + } + } + throw new Error("Batch "+gtin+" "+batchNumber+" not found in MAHs"); +} + +const productCreate = async function (conf, actor, product) { + if (!validateGtin(product.gtin)) { + const msg = "Creating product skipping invalid GTIN "+product.gtin; + console.log(msg); + return { "message": msg }; + } + const res = await jsonPost(conf, actor, { + path: `/traceability/product/create`, + body: { // see body example in follows http://swagger-mah-*.localhost:8080/#/product/post_product_create + "name": product.name, + "gtin": product.gtin, + "description": product.description + } + }); + if (!res.keySSI) { + if (conf.ignoreDups && res.message && res.message.endsWith("because it already exists.")) { + return res; + } else { + throw new Error("product/create "+product.gtin+" reply has no keySSI: "+JSON.stringify(res)); + } + } + return res; +}; + +const productsCreate = async function (conf, actor) { + // scenario default + if (conf.products === ProductsEnum.none) { + return; // don't create products + } + if (conf.products != ProductsEnum.test) { + throw new Error("Unsupported setting products=" + conf.products); + } + for (const product of actor.products) { + await productCreate(conf, actor, product); + } +}; + +const batchCreate = async function (conf, actor, gtin, batch) { + if (!validateGtin(gtin)) { + const msg = "Creating batch skipping invalid GTIN "+gtin+" for batchNumber "+batch.batchNumber; + console.log(msg); + return { "message": msg }; + } + const res = await jsonPost(conf, actor, { + path: `/traceability/batch/create`, + body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create + "gtin": gtin, + "batchNumber": batch.batchNumber, + "expiry": batch.expiry, + "serialNumbers": batch.serialNumbers + } + }); + if (!res.keySSI) { + if (conf.ignoreDups && res.message && res.message.startsWith("ConstDSU already exists!")) { + return res; + } else { + throw new Error("batch/create "+batch.batchNumber+" reply has no keySSI: "+JSON.stringify(res)); + } + } + return res; +}; + +const batchesCreateTest = async function (conf, actor) { + /* + if (actor.id.secret!="MAH136366355") { + console.log("Not MSD"); + return; + } + */ + for (const [gtin, batchArray] of Object.entries(actor.batches)) { + //console.log("Creating batch", gtin, batchArray); + for (const batch of batchArray) { + // fix expiry date on given test data + let now = new Date(); + //console.log("Batch expiry before=", batch.expiry, typeof batch.expiry); + if (!batch.expiry) { + batch.expiry = now; + } + if (batch.expiry - now < 0) { + batch.expiry.setDate(now.getDate()+365); + } + //console.log("Batch expiry=", batch.expiry); + // https://github.com/PharmaLedger-IMI/fgt-workspace/issues/69 + // issue #69 seems fixed, so we no longer truncate batches + /* + if (batch.serialNumbers.length>3600) { + console.log("Batch "+batch.batchNumber+" serialNumber has "+batch.serialNumbers.length+" elements. Truncating to 3600."); + batch.serialNumbers = batch.serialNumbers.slice(0,3599); + } + */ + await batchCreate(conf, actor, gtin, batch); + } + } +} + +const batchesCreateRandom = async function (conf, actor) { + for (const product of actor.products) { + const gtin = product.gtin; + const batches = BATCHES_RANDOM.getBatches(); // create a new array of batches with random batchNumber and random serial numbers + //console.log("new batches", batches); + for (const batch of batches) { + await batchCreate(conf, actor, gtin, batch); + // push new batches into the mah.batches + actor.batches[gtin].push(batch); + } + } +} + +const batchesCreate = async function (conf, actor) { + if (conf.batches === BatchesEnum.none) { + return; // don't create batches + } else if (conf.batches === BatchesEnum.test) { + await batchesCreateTest(conf, actor); + } else if (conf.batches === BatchesEnum.random) { + await batchesCreateRandom(conf, actor); + } else { + throw new Error("Unsupported setting batches=" + conf.batches); + } +}; + +const batchesUpdateTest = async function (conf, mah, mySales) { + // recall batch of first sold item, from the given mah + let soldProduct = undefined; + for (const sale of mySales) { + for (const product of sale.productList) { + if (product.manufName == mah.id.secret) { + soldProduct = product; + } + } + if (soldProduct) break; + } + if (!soldProduct) { + throw new Error("No sale found for "+mah.id.secret); + } + + const resQ = await jsonPut(conf, mah, { + path: `/traceability/batch/update/${encodeURI(soldProduct.gtin)}/${encodeURI(soldProduct.batchNumber)}`, + body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create + "status": BatchStatus.QUARANTINED, + "extraInfo": "Quarantined by a test script!" + } + }); + if (!resQ || !resQ.batchStatus) { + throw new Error("batch/update "+soldProduct.batchNumber+" reply has no batchStatus: "+JSON.stringify(resQ)); + } + + await sleep(SLEEP_MS); + + const resC = await jsonPut(conf, mah, { + path: `/traceability/batch/update/${encodeURI(soldProduct.gtin)}/${encodeURI(soldProduct.batchNumber)}`, + body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create + "status": BatchStatus.COMMISSIONED, + "extraInfo": "Re-comissioned by a test script!" + } + }); + if (!resC || !resC.batchStatus) { + throw new Error("batch/update "+soldProduct.batchNumber+" reply has no batchStatus: "+JSON.stringify(resC)); + } + + await sleep(SLEEP_MS); + + const resR = await jsonPut(conf, mah, { + path: `/traceability/batch/update/${encodeURI(soldProduct.gtin)}/${encodeURI(soldProduct.batchNumber)}`, + body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create + "status": BatchStatus.RECALL, + "extraInfo": "Recalled by a test script!" + } + }); + if (!resR || !resR.batchStatus) { + throw new Error("batch/update "+soldProduct.batchNumber+" reply has no batchStatus: "+JSON.stringify(resR)); + } + + await sleep(SLEEP_MS); + + return resR; +} + +const batchesUpdate = async function (conf, actor, mySales) { + if (conf.batches === BatchesEnum.none) { + return; // don't create batches + } else if (conf.batches === BatchesEnum.test) { + await batchesUpdateTest(conf, actor, mySales); + } else if (conf.batches === BatchesEnum.random) { + await batchesUpdateTest(conf, actor, mySales); + } +}; + +const shipmentCreateAndDeliver = async function(conf, sender, receiver, shipment) { + const resC = await jsonPost(conf, sender, { + path: `/traceability/shipment/create`, + body: shipment + }); + const shipmentId = genShipmentId(resC, sender.id.secret); + const receiverShipmentId = genShipmentId(resC, receiver.id.secret); + if (!shipmentId) { + throw new Error("shipment/create "+shipment+" reply has no shipmentId: "+JSON.stringify(resC)); + } + if (shipmentId !== resC.shipmentId) { + throw new Error("shipment/create "+shipment+" reply has an inconsistency in the shipmentId. Received: "+ resC.shipmentId + "Expected: "+ shipmentId); + } + await sleep(SLEEP_MS); + const resUPickup = await jsonPut(conf, sender, { + path: `/traceability/shipment/update/${encodeURI(shipmentId)}`, + body: { + "status": ShipmentStatus.PICKUP, + "extraInfo": "Ready to pick up by a test script" + } + }); + const shipmentId2 = resUPickup.shipmentId; + if (!shipmentId2) { + throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUPickup)); + } + await sleep(SLEEP_MS); + const resUTransit = await jsonPut(conf, sender, { + path: `/traceability/shipment/update/${encodeURI(shipmentId)}`, + body: { + "status": ShipmentStatus.TRANSIT, + "extraInfo": "Picked up in good condition by a test script!" + } + }); + const shipmentId3 = resUTransit.shipmentId; + if (!shipmentId3) { + throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUTransit)); + } + await sleep(SLEEP_MS); + const resUDelivered = await jsonPut(conf, sender, { + path: `/traceability/shipment/update/${encodeURI(shipmentId)}`, + body: { + "status": ShipmentStatus.DELIVERED, + "extraInfo": "Delivered in good condition by a test script!" + } + }); + const shipmentId4 = resUDelivered.shipmentId; + if (!shipmentId4) { + throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUDelivered)); + } + await sleep(SLEEP_MS); + const resUReceived = await jsonPut(conf, receiver, { + path: `/traceability/shipment/update/${encodeURI(receiverShipmentId)}`, + body: { + "status": ShipmentStatus.RECEIVED, + "extraInfo": "Received in good condition by a test script!" + } + }); + const shipmentId5 = resUReceived.shipmentId; + if (!shipmentId5) { + throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUReceived)); + } + await sleep(SLEEP_MS); + const resUConfirmed = await jsonPut(conf, receiver, { + path: `/traceability/shipment/update/${encodeURI(receiverShipmentId)}`, + body: { + "status": ShipmentStatus.CONFIRMED, + "extraInfo": "Confirmed into stock by a test script!" + } + }); + const shipmentId6 = resUConfirmed.shipmentId; + if (!shipmentId6) { + throw new Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUConfirmed)); + } + + await sleep(SLEEP_MS); + + return resUConfirmed; +}; + + +const shipmentsCreateTest = async function (conf, sender) { + if (conf.scenario==ScenarioEnum.dfm) { + return shipmentsCreateTestDfm(conf, sender); + } + return shipmentsCreateTestDefault(conf, sender); +} + +const shipmentsCreateTestDfm = async function (conf, sender) { + if (!sender.id.secret.startsWith("MAH")) { + throw new Error("shipmentsCreateTestDfm can only send for an MAH"); + } + + const whs = WSH1; + const pha = PHA1; + + for (const product of sender.products) { // ship all DFM products + const gtin = product.gtin; + if (gtin=='02113100000028' || gtin=='07613421039424') continue; + for (const batch of sender.batches[gtin]) { // ship all DFM batches + const batchNumber = batch.batchNumber; + const quantity = batch.quantity; + + const shipment1MahToWhs = { + "orderId": whs.id.secret + "-" + (new Date()).toISOString(), + "requesterId": whs.id.secret, + "shipmentLines": [ + { + "gtin": gtin, + "batch": batchNumber, + "quantity": quantity + } + ] + }; + + await shipmentCreateAndDeliver(conf, sender, whs, shipment1MahToWhs); + + const shipment2WhsToPha = { + "orderId": pha.id.secret + "-" + (new Date()).toISOString(), + "requesterId": pha.id.secret, + "shipmentLines": [ + { + "gtin": gtin, + "batch": batchNumber, + "quantity": quantity + } + ] + }; + + const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); + SHIPMENTS_ON_PHA.push(resShipToPha); + } + } +} + +const shipmentsCreateTestDefault = async function (conf, sender) { + if (sender.id.secret != MAH_MSD.id.secret) { + throw new Error("shipmentsCreateTest can only sell for MSD for now"); + } + + const whs = WSH1; + const pha = PHA1; + + const shipment1MsdToWhs = { + "orderId": whs.id.secret + "-" + (new Date()).toISOString(), + "requesterId": whs.id.secret, + "shipmentLines": [ + { + "gtin": "00366582505358", + "batch": "R034995", + "quantity": 100 + }, + { + "gtin": "00191778005295", + "batch": "U002114", + "quantity": 100 + } + ] + }; + + await shipmentCreateAndDeliver(conf, sender, whs, shipment1MsdToWhs); + + const shipment2WhsToPha = { + "orderId": pha.id.secret + "-" + (new Date()).toISOString(), + "requesterId": pha.id.secret, + "shipmentLines": [ + { + "gtin": "00366582505358", + "batch": "R034995", + "quantity": 50 + }, + { + "gtin": "00191778005295", + "batch": "U002114", + "quantity": 50 + } + ] + }; + + const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); + SHIPMENTS_ON_PHA.push(resShipToPha); +} + +const shipmentsCreateRandom = async function (conf, sender) { + if (sender.id.secret != MAH_MSD.id.secret) { + throw new Error("shipmentsCreateTest can only sell for MSD for now"); + } + + const mahGtins = Object.keys(sender.batches); + const mahRandomGtin = mahGtins[generateRandomInt(0, mahGtins.length)]; + const mahBatch0 = sender.batches[mahRandomGtin][0]; + const whs = WSH1; + const pha = PHA1; + + const shipment1MahToWhs = { + "orderId": whs.id.secret + "-" + (new Date()).toISOString(), + "requesterId": whs.id.secret, + "shipmentLines": [ + { + "gtin": mahRandomGtin, + "batch": mahBatch0.batchNumber, + "quantity": 100 + } + ] + }; + + await shipmentCreateAndDeliver(conf, sender, whs, shipment1MahToWhs); + + const shipment2WhsToPha = { + "orderId": pha.id.secret + "-" + (new Date()).toISOString(), + "requesterId": pha.id.secret, + "shipmentLines": [ + { + "gtin": mahRandomGtin, + "batch": mahBatch0.batchNumber, + "quantity": 50 + } + ] + }; + + const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); + SHIPMENTS_ON_PHA.push(resShipToPha); +} + +const shipmentsCreate = async function (conf, sender) { + if (conf.shipments === ShipmentsEnum.none) { + return; // don't create batches + } else if (conf.shipments === ShipmentsEnum.test) { + await shipmentsCreateTest(conf, sender); + } else if (conf.shipments === ShipmentsEnum.random) { + await shipmentsCreateRandom(conf, sender); + } else { + throw new Error("Unsupported setting shipments=" + conf.shipments); + } +}; + +/* +const salesCreateTest = async function (conf, manufActor, sellerActor, mySales) { + const manufBatches = manufActor.batches; + const gtin = "00366582505358"; + const batch = manufBatches[gtin][0]; + //console.log("batch", batch); + + let i=0; + while (i Date: Wed, 19 Oct 2022 16:10:43 +0100 Subject: [PATCH 7/9] #119 - this script was not actually needed --- bin/environment/wsCreateStuffDfm2.js | 1015 -------------------------- 1 file changed, 1015 deletions(-) delete mode 100644 bin/environment/wsCreateStuffDfm2.js diff --git a/bin/environment/wsCreateStuffDfm2.js b/bin/environment/wsCreateStuffDfm2.js deleted file mode 100644 index dc6176f8..00000000 --- a/bin/environment/wsCreateStuffDfm2.js +++ /dev/null @@ -1,1015 +0,0 @@ -/** - * Fork of wsCreateStuff.js for a specific DFM situation: - * https://github.com/PharmaLedger-IMI/fgt-workspace/issues/119#issuecomment-1283748884 - * - * Delete it, if you do not know what you would need it for... :-) - * - */ - -const http = require('http'); -const https = require('https'); - -const { argParser, validateGtin, generateRandomInt } = require('./utils'); -const { encodeBase64 } = require('../../fgt-api/utils/basicAuth'); - -const ShipmentStatus = require('../../fgt-dsu-wizard/model/ShipmentStatus'); -const BatchStatus = require('../../fgt-dsu-wizard/model/BatchStatus'); - -const credentials = require('./credentials/credentialsTests'); // TODO require ../../docker/api/env/mah-*.json ? -const MAHS = [credentials.PFIZER, credentials.MSD, credentials.ROCHE, credentials.BAYER, credentials.NOVO_NORDISK, credentials.GSK, credentials.TAKEDA, credentials.SANOFI]; -const MAH_MSD = credentials.MSD; -// #106 test one participant with credentials overridden by environment on docker-compose.yml -// MAH_MSD.id.secret="MAH0000000"; -const MAH_ROCHE = credentials.ROCHE; -// #106 test one participant with credentials overridden by environment on docker-compose.yml -// MAH_ROCHE.id.secret="MAH0000000"; -const MAH_BAYER = credentials.BAYER; -const WSH1 = require("../../docker/api/env/whs-1.json"); -const WSH2 = require("../../docker/api/env/whs-2.json"); -const PHA1 = require("../../docker/api/env/pha-1.json"); -const PHA2 = require("../../docker/api/env/pha-2.json"); -const SHIPMENTS_ON_PHA = []; // records all shipments sent to a PHA, so that they can be sold. - -const NUM_SALES = 2; // number of sales to perform - for now consume serialNumbers from 1st MSD batch -const MY_SALES = []; // array of data returned by /sale/create - -let SLEEP_MS = 2000; - -const PRODUCTS_TEST = require('./products/productsTests'); -const BATCHES_TEST = require('./batches/batchesTests'); -const BATCHES_RANDOM = require('./batches/batchesRandom'); - - - -class ProductsEnum { - static none = "none"; - static test = "test"; -}; - -class BatchesEnum { - static none = "none"; - static test = "test"; - static random = "random"; -}; - -class ShipmentsEnum { - static none = "none"; - static test = "test"; - static random = "random"; -}; - -class SalesEnum { - static none = "none"; - static test = "test"; -}; - -class TraceabilityEnum { - static none = "none"; - static test = "test"; -}; - -class ReceiptsEnum { - static none = "none"; - static test = "test"; -}; - -class ScenarioEnum { - static single = "single"; - static default = "default"; - static dfm = "dfm"; // dfm is acdc - static dfm2 = "dfm2"; // dfm is acdc -}; - -function genShipmentId(simpleShipment, identityId) { - let shipmentId; - const splitShipmentId = `${simpleShipment.shipmentId}`.split('-'); - if (identityId === simpleShipment.senderId) { - if (splitShipmentId.length >= 2) - shipmentId = splitShipmentId[splitShipmentId.length - 1]; - else - shipmentId = simpleShipment.shipmentId; - } else { - if (splitShipmentId.length >= 2) - shipmentId = simpleShipment.shipmentId; - else - shipmentId = `${simpleShipment.senderId}-${simpleShipment.shipmentId}`; - } - return shipmentId; -} - -const defaultOps = { - ignoreDups: "t", // falsy will - wsProtocol: "http", - wsDomainSuffix: ".localhost", - wsPortNumber: "8080", - env: "localhost", - products: ProductsEnum.test, - batches: BatchesEnum.test, - shipments: ShipmentsEnum.test, - sales: SalesEnum.test, - traceability: TraceabilityEnum.test, - receipts: ReceiptsEnum.test, - scenario: ScenarioEnum.default, - sleep: "2000" -} - -if (process.argv.includes("--help") - || process.argv.includes("-h") - || process.argv.includes("-?") -) { - console.log("Usage:"); - console.log(); - console.log("\tnode --unhandled-rejections=strict wsCreateStuff.js [options]"); - console.log(); - console.log("Where options can be any of:"); - console.log(); - console.log("\t--env=single|localhost*|dev|tst single is for a single MAH on port 8081"); - console.log("\t--ignoreDups=t*| only for product and batch creation"); - console.log("\t--sleep=2000 number of ms to sleep between API REST calls"); - console.log(); - console.log("\t--batches=none|test*|random"); - console.log("\t--products=none|test*"); - console.log("\t--shipments=none|test*|random"); - console.log("\t--sales=none|test*"); - console.log("\t--receipts=none|test*"); - console.log("\t--traceability=none|test*"); - console.log(); - console.log("\t--scenario=single|default*|dfm The single scenario only creates products and batches"); - console.log("\t\tfor a single specifc MAH. The default scenario will create products, batches,"); - console.log("\t\tshipments, sales, receipts, more shipments, more sales, more receipts,"); - console.log("\t\tthen quarantine one batch, and then recall one batch. The dfm scenario"); - console.log("\t\tcreates some specific producs, batches, shipments and sales for a DFM demo."); - console.log(); - console.log("* - is the default setting"); - process.exit(0); -} - -const conf = argParser(defaultOps, process.argv); - -if (conf.env === "single") { - conf.wsPortNumber = "8081"; -} else if (conf.env === "dev") { - conf.wsDomainSuffix = "-fgt-dev.pharmaledger.pdmfc.com"; - conf.wsPortNumber = "443"; - conf.wsProtocol = "https"; -} else if (conf.env === "tst") { - conf.wsDomainSuffix = "-fgt.pharmaledger.pdmfc.com"; - conf.wsPortNumber = "443"; - conf.wsProtocol = "https"; -} - -if (conf.sleep) { - SLEEP_MS = parseInt(conf.sleep); -} - -/** - * - * Functions - */ - -// Based on -// https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep -function sleep(millis) { - console.log("Sleep "+millis+"ms"); - return new Promise(resolve => setTimeout(resolve, millis)); -} - -// Based on -// https://stackoverflow.com/questions/6158933/how-is-an-http-post-request-made-in-node-js -const jsonHttpRequest = function (conf, actor, { body, ...options }) { - const bodyToSend = (body && typeof body != "string") ? JSON.stringify(body) : body; - - if (!options.headers) { - options.headers = { - 'content-type': 'application/json', - }; - } else if (!options.headers['content-type']) { - options.headers['content-type'] = 'application/json'; - } - if (bodyToSend) - options.headers['content-length'] = Buffer.byteLength(bodyToSend); - if (!options['hostname']) - options.hostname = getHostnameForActor(conf, actor); - if (!options['port']) - options.port = conf.wsPortNumber; - if (!options.headers['Authorization']) { - const secret = `${actor.id.secret}:${(actor.pass.secret)}`; - options.headers['Authorization'] = `Basic ${encodeBase64(secret)}`; - } - - - const beforeReq = new Date(); - const protocol = conf.wsProtocol; - let p = new Promise((resolve, reject) => { - // debug request - console.log((new Date()).toISOString()+": "+protocol+" "+options.method, JSON.stringify(options), bodyToSend); - - const req = (protocol === "http" ? http : https).request( - { - ...options, - }, - res => { - const chunks = []; - res.on('data', data => chunks.push(data)); - res.on('end', () => { - let resBody = Buffer.concat(chunks); - //console.log("res.headers=", res.headers); - const contentType = res.headers['content-type']; - if (contentType && contentType.startsWith('application/json')) { - resolve(JSON.parse(resBody.toString())); // seems to be a JSON reply. Attempt to parse. - } else if (contentType && contentType.startsWith('text/')) { - resolve(resBody.toString()); // seems to be readable text. - } else { - resolve(resBody); // don't know what content-type is this. Return it as a Buffer. - } - }); - } - ); - req.on('error', reject); - if (bodyToSend) { - req.write(bodyToSend); - } - req.end(); - }); - - // debug reply - p.then((r) => { - const afterRes = new Date(); - const ellapsed = afterRes.getTime()-beforeReq.getTime(); - console.log(`res ${ellapsed}ms`, r); - }); - - return p; -} - -const jsonGet = function (conf, actor, { body, ...options }) { - options.method = "GET"; - return jsonHttpRequest(conf, actor, { body, ...options }); -} - -const jsonPost = function (conf, actor, { body, ...options }) { - options.method = "POST"; - return jsonHttpRequest(conf, actor, { body, ...options }); -} - -const jsonPut = function (conf, actor, { body, ...options }) { - options.method = "PUT"; - return jsonHttpRequest(conf, actor, { body, ...options }); -} - -const getHostnameForActor = function (conf, actor) { - if (conf.env=="single") { - return "localhost"; - } - // test MAH - let mahMatch = actor.email.secret.match(/^(.*)@mah.*$/); - if (mahMatch) { - let mahName = mahMatch[1].replace(".", "-"); - // special case merck->msd - if (mahName === "merck") - mahName = "msd"; - return `api-mah-${mahName}${conf.wsDomainSuffix}`; - } - // test WHS - let whsMatch = actor.id.secret.match(/^WHS([0-9]+)$/); - if (whsMatch) { - let whsNumber = parseInt(whsMatch[1])+""; // eliminate leading zeros - // taked is special - if (whsNumber==="999999") - whsNumber = "takeda"; - return `api-whs${whsNumber}${conf.wsDomainSuffix}`; - } - // test PHA - let phaMatch = actor.id.secret.match(/^PHA([0-9]+)$/); - if (phaMatch) { - let phaNumber = parseInt(phaMatch[1])+""; // eliminate leading zeros - return `api-pha${phaNumber}${conf.wsDomainSuffix}`; - } - throw new Error("Cannot determine hostname for actor.email=" + actor.email.secret); - //return undefined; -} - -const findMahOriginalBatch = function (gtin, batchNumber) { - //for(const mah of [MAH_MSD]) { // only MSD has good prod+batches - for(const mah of MAHS) { - const batches = mah.batches; - //console.log("Lookging for "+gtin+" "+batchNumber+" in", batches); - if (!batches) continue; - if (gtin in batches) { - const aBatchArray = batches[gtin]; - for (const batch of aBatchArray) { - if (batchNumber == batch.batchNumber) - return batch; - } - } - } - throw new Error("Batch "+gtin+" "+batchNumber+" not found in MAHs"); -} - -const productCreate = async function (conf, actor, product) { - if (!validateGtin(product.gtin)) { - const msg = "Creating product skipping invalid GTIN "+product.gtin; - console.log(msg); - return { "message": msg }; - } - const res = await jsonPost(conf, actor, { - path: `/traceability/product/create`, - body: { // see body example in follows http://swagger-mah-*.localhost:8080/#/product/post_product_create - "name": product.name, - "gtin": product.gtin, - "description": product.description - } - }); - if (!res.keySSI) { - if (conf.ignoreDups && res.message && res.message.endsWith("because it already exists.")) { - return res; - } else { - throw new Error("product/create "+product.gtin+" reply has no keySSI: "+JSON.stringify(res)); - } - } - return res; -}; - -const productsCreate = async function (conf, actor) { - // scenario default - if (conf.products === ProductsEnum.none) { - return; // don't create products - } - if (conf.products != ProductsEnum.test) { - throw new Error("Unsupported setting products=" + conf.products); - } - for (const product of actor.products) { - await productCreate(conf, actor, product); - } -}; - -const batchCreate = async function (conf, actor, gtin, batch) { - if (!validateGtin(gtin)) { - const msg = "Creating batch skipping invalid GTIN "+gtin+" for batchNumber "+batch.batchNumber; - console.log(msg); - return { "message": msg }; - } - const res = await jsonPost(conf, actor, { - path: `/traceability/batch/create`, - body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create - "gtin": gtin, - "batchNumber": batch.batchNumber, - "expiry": batch.expiry, - "serialNumbers": batch.serialNumbers - } - }); - if (!res.keySSI) { - if (conf.ignoreDups && res.message && res.message.startsWith("ConstDSU already exists!")) { - return res; - } else { - throw new Error("batch/create "+batch.batchNumber+" reply has no keySSI: "+JSON.stringify(res)); - } - } - return res; -}; - -const batchesCreateTest = async function (conf, actor) { - /* - if (actor.id.secret!="MAH136366355") { - console.log("Not MSD"); - return; - } - */ - for (const [gtin, batchArray] of Object.entries(actor.batches)) { - //console.log("Creating batch", gtin, batchArray); - for (const batch of batchArray) { - // fix expiry date on given test data - let now = new Date(); - //console.log("Batch expiry before=", batch.expiry, typeof batch.expiry); - if (!batch.expiry) { - batch.expiry = now; - } - if (batch.expiry - now < 0) { - batch.expiry.setDate(now.getDate()+365); - } - //console.log("Batch expiry=", batch.expiry); - // https://github.com/PharmaLedger-IMI/fgt-workspace/issues/69 - // issue #69 seems fixed, so we no longer truncate batches - /* - if (batch.serialNumbers.length>3600) { - console.log("Batch "+batch.batchNumber+" serialNumber has "+batch.serialNumbers.length+" elements. Truncating to 3600."); - batch.serialNumbers = batch.serialNumbers.slice(0,3599); - } - */ - await batchCreate(conf, actor, gtin, batch); - } - } -} - -const batchesCreateRandom = async function (conf, actor) { - for (const product of actor.products) { - const gtin = product.gtin; - const batches = BATCHES_RANDOM.getBatches(); // create a new array of batches with random batchNumber and random serial numbers - //console.log("new batches", batches); - for (const batch of batches) { - await batchCreate(conf, actor, gtin, batch); - // push new batches into the mah.batches - actor.batches[gtin].push(batch); - } - } -} - -const batchesCreate = async function (conf, actor) { - if (conf.batches === BatchesEnum.none) { - return; // don't create batches - } else if (conf.batches === BatchesEnum.test) { - await batchesCreateTest(conf, actor); - } else if (conf.batches === BatchesEnum.random) { - await batchesCreateRandom(conf, actor); - } else { - throw new Error("Unsupported setting batches=" + conf.batches); - } -}; - -const batchesUpdateTest = async function (conf, mah, mySales) { - // recall batch of first sold item, from the given mah - let soldProduct = undefined; - for (const sale of mySales) { - for (const product of sale.productList) { - if (product.manufName == mah.id.secret) { - soldProduct = product; - } - } - if (soldProduct) break; - } - if (!soldProduct) { - throw new Error("No sale found for "+mah.id.secret); - } - - const resQ = await jsonPut(conf, mah, { - path: `/traceability/batch/update/${encodeURI(soldProduct.gtin)}/${encodeURI(soldProduct.batchNumber)}`, - body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create - "status": BatchStatus.QUARANTINED, - "extraInfo": "Quarantined by a test script!" - } - }); - if (!resQ || !resQ.batchStatus) { - throw new Error("batch/update "+soldProduct.batchNumber+" reply has no batchStatus: "+JSON.stringify(resQ)); - } - - await sleep(SLEEP_MS); - - const resC = await jsonPut(conf, mah, { - path: `/traceability/batch/update/${encodeURI(soldProduct.gtin)}/${encodeURI(soldProduct.batchNumber)}`, - body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create - "status": BatchStatus.COMMISSIONED, - "extraInfo": "Re-comissioned by a test script!" - } - }); - if (!resC || !resC.batchStatus) { - throw new Error("batch/update "+soldProduct.batchNumber+" reply has no batchStatus: "+JSON.stringify(resC)); - } - - await sleep(SLEEP_MS); - - const resR = await jsonPut(conf, mah, { - path: `/traceability/batch/update/${encodeURI(soldProduct.gtin)}/${encodeURI(soldProduct.batchNumber)}`, - body: { // see body example in https://swagger-mah-*-fgt-dev.pharmaledger.pdmfc.com/#/batch/post_batch_create - "status": BatchStatus.RECALL, - "extraInfo": "Recalled by a test script!" - } - }); - if (!resR || !resR.batchStatus) { - throw new Error("batch/update "+soldProduct.batchNumber+" reply has no batchStatus: "+JSON.stringify(resR)); - } - - await sleep(SLEEP_MS); - - return resR; -} - -const batchesUpdate = async function (conf, actor, mySales) { - if (conf.batches === BatchesEnum.none) { - return; // don't create batches - } else if (conf.batches === BatchesEnum.test) { - await batchesUpdateTest(conf, actor, mySales); - } else if (conf.batches === BatchesEnum.random) { - await batchesUpdateTest(conf, actor, mySales); - } -}; - -const shipmentCreateAndDeliver = async function(conf, sender, receiver, shipment) { - const resC = await jsonPost(conf, sender, { - path: `/traceability/shipment/create`, - body: shipment - }); - const shipmentId = genShipmentId(resC, sender.id.secret); - const receiverShipmentId = genShipmentId(resC, receiver.id.secret); - if (!shipmentId) { - throw new Error("shipment/create "+shipment+" reply has no shipmentId: "+JSON.stringify(resC)); - } - if (shipmentId !== resC.shipmentId) { - throw new Error("shipment/create "+shipment+" reply has an inconsistency in the shipmentId. Received: "+ resC.shipmentId + "Expected: "+ shipmentId); - } - await sleep(SLEEP_MS); - const resUPickup = await jsonPut(conf, sender, { - path: `/traceability/shipment/update/${encodeURI(shipmentId)}`, - body: { - "status": ShipmentStatus.PICKUP, - "extraInfo": "Ready to pick up by a test script" - } - }); - const shipmentId2 = resUPickup.shipmentId; - if (!shipmentId2) { - throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUPickup)); - } - await sleep(SLEEP_MS); - const resUTransit = await jsonPut(conf, sender, { - path: `/traceability/shipment/update/${encodeURI(shipmentId)}`, - body: { - "status": ShipmentStatus.TRANSIT, - "extraInfo": "Picked up in good condition by a test script!" - } - }); - const shipmentId3 = resUTransit.shipmentId; - if (!shipmentId3) { - throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUTransit)); - } - await sleep(SLEEP_MS); - const resUDelivered = await jsonPut(conf, sender, { - path: `/traceability/shipment/update/${encodeURI(shipmentId)}`, - body: { - "status": ShipmentStatus.DELIVERED, - "extraInfo": "Delivered in good condition by a test script!" - } - }); - const shipmentId4 = resUDelivered.shipmentId; - if (!shipmentId4) { - throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUDelivered)); - } - await sleep(SLEEP_MS); - const resUReceived = await jsonPut(conf, receiver, { - path: `/traceability/shipment/update/${encodeURI(receiverShipmentId)}`, - body: { - "status": ShipmentStatus.RECEIVED, - "extraInfo": "Received in good condition by a test script!" - } - }); - const shipmentId5 = resUReceived.shipmentId; - if (!shipmentId5) { - throw Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUReceived)); - } - await sleep(SLEEP_MS); - const resUConfirmed = await jsonPut(conf, receiver, { - path: `/traceability/shipment/update/${encodeURI(receiverShipmentId)}`, - body: { - "status": ShipmentStatus.CONFIRMED, - "extraInfo": "Confirmed into stock by a test script!" - } - }); - const shipmentId6 = resUConfirmed.shipmentId; - if (!shipmentId6) { - throw new Error("shipment/update "+shipmentId+" reply has no shipmentId: "+JSON.stringify(resUConfirmed)); - } - - await sleep(SLEEP_MS); - - return resUConfirmed; -}; - - -const shipmentsCreateTest = async function (conf, sender) { - if (conf.scenario==ScenarioEnum.dfm) { - return shipmentsCreateTestDfm(conf, sender); - } - return shipmentsCreateTestDefault(conf, sender); -} - -const shipmentsCreateTestDfm = async function (conf, sender) { - if (!sender.id.secret.startsWith("MAH")) { - throw new Error("shipmentsCreateTestDfm can only send for an MAH"); - } - - const whs = WSH1; - const pha = PHA1; - - for (const product of sender.products) { // ship all DFM products - const gtin = product.gtin; - if (gtin=='02113100000028' || gtin=='07613421039424') continue; - for (const batch of sender.batches[gtin]) { // ship all DFM batches - const batchNumber = batch.batchNumber; - const quantity = batch.quantity; - - const shipment1MahToWhs = { - "orderId": whs.id.secret + "-" + (new Date()).toISOString(), - "requesterId": whs.id.secret, - "shipmentLines": [ - { - "gtin": gtin, - "batch": batchNumber, - "quantity": quantity - } - ] - }; - - await shipmentCreateAndDeliver(conf, sender, whs, shipment1MahToWhs); - - const shipment2WhsToPha = { - "orderId": pha.id.secret + "-" + (new Date()).toISOString(), - "requesterId": pha.id.secret, - "shipmentLines": [ - { - "gtin": gtin, - "batch": batchNumber, - "quantity": quantity - } - ] - }; - - const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); - SHIPMENTS_ON_PHA.push(resShipToPha); - } - } -} - -const shipmentsCreateTestDefault = async function (conf, sender) { - if (sender.id.secret != MAH_MSD.id.secret) { - throw new Error("shipmentsCreateTest can only sell for MSD for now"); - } - - const whs = WSH1; - const pha = PHA1; - - const shipment1MsdToWhs = { - "orderId": whs.id.secret + "-" + (new Date()).toISOString(), - "requesterId": whs.id.secret, - "shipmentLines": [ - { - "gtin": "00366582505358", - "batch": "R034995", - "quantity": 100 - }, - { - "gtin": "00191778005295", - "batch": "U002114", - "quantity": 100 - } - ] - }; - - await shipmentCreateAndDeliver(conf, sender, whs, shipment1MsdToWhs); - - const shipment2WhsToPha = { - "orderId": pha.id.secret + "-" + (new Date()).toISOString(), - "requesterId": pha.id.secret, - "shipmentLines": [ - { - "gtin": "00366582505358", - "batch": "R034995", - "quantity": 50 - }, - { - "gtin": "00191778005295", - "batch": "U002114", - "quantity": 50 - } - ] - }; - - const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); - SHIPMENTS_ON_PHA.push(resShipToPha); -} - -const shipmentsCreateRandom = async function (conf, sender) { - if (sender.id.secret != MAH_MSD.id.secret) { - throw new Error("shipmentsCreateTest can only sell for MSD for now"); - } - - const mahGtins = Object.keys(sender.batches); - const mahRandomGtin = mahGtins[generateRandomInt(0, mahGtins.length)]; - const mahBatch0 = sender.batches[mahRandomGtin][0]; - const whs = WSH1; - const pha = PHA1; - - const shipment1MahToWhs = { - "orderId": whs.id.secret + "-" + (new Date()).toISOString(), - "requesterId": whs.id.secret, - "shipmentLines": [ - { - "gtin": mahRandomGtin, - "batch": mahBatch0.batchNumber, - "quantity": 100 - } - ] - }; - - await shipmentCreateAndDeliver(conf, sender, whs, shipment1MahToWhs); - - const shipment2WhsToPha = { - "orderId": pha.id.secret + "-" + (new Date()).toISOString(), - "requesterId": pha.id.secret, - "shipmentLines": [ - { - "gtin": mahRandomGtin, - "batch": mahBatch0.batchNumber, - "quantity": 50 - } - ] - }; - - const resShipToPha = await shipmentCreateAndDeliver(conf, whs, pha, shipment2WhsToPha); - SHIPMENTS_ON_PHA.push(resShipToPha); -} - -const shipmentsCreate = async function (conf, sender) { - if (conf.shipments === ShipmentsEnum.none) { - return; // don't create batches - } else if (conf.shipments === ShipmentsEnum.test) { - await shipmentsCreateTest(conf, sender); - } else if (conf.shipments === ShipmentsEnum.random) { - await shipmentsCreateRandom(conf, sender); - } else { - throw new Error("Unsupported setting shipments=" + conf.shipments); - } -}; - -/* -const salesCreateTest = async function (conf, manufActor, sellerActor, mySales) { - const manufBatches = manufActor.batches; - const gtin = "00366582505358"; - const batch = manufBatches[gtin][0]; - //console.log("batch", batch); - - let i=0; - while (i Date: Sat, 22 Oct 2022 19:05:30 +0100 Subject: [PATCH 8/9] #122 - example of 2 proxies using apache httpd --- apihub-root/external-volume/config/bdns.hosts | 6 +- .../config/fgt-mah-wallet/credentials.json | 6 +- tests/proxy/Dockerfile | 10 + tests/proxy/README.md | 115 ++++ tests/proxy/httpd_original.conf | 551 +++++++++++++++++ tests/proxy/httpd_proxypass.conf | 577 ++++++++++++++++++ 6 files changed, 1259 insertions(+), 6 deletions(-) create mode 100644 tests/proxy/Dockerfile create mode 100644 tests/proxy/README.md create mode 100644 tests/proxy/httpd_original.conf create mode 100644 tests/proxy/httpd_proxypass.conf diff --git a/apihub-root/external-volume/config/bdns.hosts b/apihub-root/external-volume/config/bdns.hosts index f8bcebe9..f9711e63 100644 --- a/apihub-root/external-volume/config/bdns.hosts +++ b/apihub-root/external-volume/config/bdns.hosts @@ -11,13 +11,13 @@ "traceability": { "replicas": [], "brickStorages": [ - "$ORIGIN" + "http://localhost:8808" ], "mqEndpoints": [ - "$ORIGIN" + "http://localhost:8808" ], "anchoringServices": [ - "$ORIGIN" + "http://localhost:8808" ] }, "epi": { diff --git a/fgt-api/config/fgt-mah-wallet/credentials.json b/fgt-api/config/fgt-mah-wallet/credentials.json index 215ac00d..b83ff881 100644 --- a/fgt-api/config/fgt-mah-wallet/credentials.json +++ b/fgt-api/config/fgt-mah-wallet/credentials.json @@ -1,14 +1,14 @@ { "name": { - "secret": "F. Hoffmann-La Roche AG", + "secret": "PDM-JPSL", "public": true }, "id": { - "secret": "MAH116267986", + "secret": "MAH-PDM-JPSL", "public": true }, "email": { - "secret": "roche@mah.pharmaledger.com", + "secret": "pdm-jpsl@mah.pharmaledger.com", "public": true }, "address": { diff --git a/tests/proxy/Dockerfile b/tests/proxy/Dockerfile new file mode 100644 index 00000000..def59742 --- /dev/null +++ b/tests/proxy/Dockerfile @@ -0,0 +1,10 @@ +# The Base Image used to create this Image +FROM httpd:2.4.54 + +# to Copy a file named httpd_proxypass.conf from present working directory to the /usr/local/apache2/conf inside the container +# This is taken from the original httpd.conf inside the base image, and modified to allow ProxyPass +COPY httpd_proxypass.conf /usr/local/apache2/conf/httpd.conf + +EXPOSE 8808 + +CMD ["httpd-foreground"] \ No newline at end of file diff --git a/tests/proxy/README.md b/tests/proxy/README.md new file mode 100644 index 00000000..089b21f8 --- /dev/null +++ b/tests/proxy/README.md @@ -0,0 +1,115 @@ +# FGT participant going through 2 proxies + +A short example of configuring an FGT participant using a chain of 2 proxies. +- a static proxy (running at http://localhos:8808 on this example) called httpd-proxy-static that always forwards all requests to https://fgt-dev.pharmaledger.pdmfc.com through a generic proxy (also configured statically - see below). +- a generic proxy (a squid proxy running on http://pdm-00781:3128 for this example) + +Port numbers provided are just for example completness. Should be changed to whatever you need. + +## DISCLAIMER + +This configuration is not security-validated. A lot of apache's default configuration should be removed/inhibited for production purposes. + +But this example should be enough to see the Proxy configuration directives required. + +(This example was not validated on an environment where the apache was prevented to connect to the internet - as in this example would loose also access to the squid proxy also.) + + +## Configure an apache httpd 2.4.54 as a static proxy inside a docker + +### Edit the static proxy config + +Edit the tests/proxy/httpd_proxypass.conf to suite your configs. +The most relevant are at the bottom + +```xml +# Global config + +SSLProxyEngine on +# all external accesses should go through this proxy (this is my local squid) +# PLACE YOUR OPENSHIFT PROXY HERE - the one that is defined by the https_proxy variable +ProxyRemote * http://pdm-00781:3128 + +NameVirtualHost * + + ServerName owncloud.mydomain.com + + ProxyRequests Off + + Order deny,allow + Allow from all + + + # pass everything to https://fgt-dev.pharmaledger.pdmfc.com + # use https://fgt.pharmaledger.pdmfc.com when confident + + ProxyPass / https://fgt-dev.pharmaledger.pdmfc.com/ + ProxyPassReverse / https://fgt-dev.pharmaledger.pdmfc.com/ + + Order allow,deny + Allow from all + + +``` + +Compare (diff) with httpd_original.conf +(note that it is listening on 8088, and needs to load proxy_module proxy_http_module ssl_module) + +### Build the static proxy + +```sh +docker build -t httpd-proxy-static . +``` + +### Run the static proxy as a standalone docker at port 8808 + +```sh +docker run --network="host" -p 8808:8808 httpd-proxy-static +``` + +The `--network="host"` was needed just to connect to the squid proxy at http://pdm-00781:3128 +but, your docker container should have connection to your generic proxy without further configs. + +### Edit the apihub-root/external-volume/config/bdns.hosts so that the domain traceability goes through the proxy + +The domain traceability should go through the static proxy. +Note that it is an http (not https) proxy. + +In this example, as the static proxy is running at http://localhost:8808, that is the address we use. +( Do not confuse with the squid running at http://pdm-00781:3128 ). + +```json + "traceability": { + "replicas": [], + "brickStorages": [ + "http://localhost:8808" + ], + "mqEndpoints": [ + "http://localhost:8808" + ], + "anchoringServices": [ + "http://localhost:8808" + ] + }, +``` + + +## Notes on how to install and run a squid proxy on Ubuntu 22 + +```sh +sudo apt install squid +``` + +Squid will be left running on port 3128. + +To test, configure a browser using a proxy at localhost:3128 (or pdm-00781:3121), +test access to a web page, and check /var/log/squid/access.log that all +this browser's accesses go through this proxy. + +systemctl enable squid +systemctl start squid + +systemctl status squid + +systemctl stop squid +systemctl disable squid diff --git a/tests/proxy/httpd_original.conf b/tests/proxy/httpd_original.conf new file mode 100644 index 00000000..1ccfb02f --- /dev/null +++ b/tests/proxy/httpd_original.conf @@ -0,0 +1,551 @@ +# +# This is the main Apache HTTP server configuration file. It contains the +# configuration directives that give the server its instructions. +# See for detailed information. +# In particular, see +# +# for a discussion of each configuration directive. +# +# Do NOT simply read the instructions in here without understanding +# what they do. They're here only as hints or reminders. If you are unsure +# consult the online docs. You have been warned. +# +# Configuration and logfile names: If the filenames you specify for many +# of the server's control files begin with "/" (or "drive:/" for Win32), the +# server will use that explicit path. If the filenames do *not* begin +# with "/", the value of ServerRoot is prepended -- so "logs/access_log" +# with ServerRoot set to "/usr/local/apache2" will be interpreted by the +# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log" +# will be interpreted as '/logs/access_log'. + +# +# ServerRoot: The top of the directory tree under which the server's +# configuration, error, and log files are kept. +# +# Do not add a slash at the end of the directory path. If you point +# ServerRoot at a non-local disk, be sure to specify a local disk on the +# Mutex directive, if file-based mutexes are used. If you wish to share the +# same ServerRoot for multiple httpd daemons, you will need to change at +# least PidFile. +# +ServerRoot "/usr/local/apache2" + +# +# Mutex: Allows you to set the mutex mechanism and mutex file directory +# for individual mutexes, or change the global defaults +# +# Uncomment and change the directory if mutexes are file-based and the default +# mutex file directory is not on a local disk or is not appropriate for some +# other reason. +# +# Mutex default:logs + +# +# Listen: Allows you to bind Apache to specific IP addresses and/or +# ports, instead of the default. See also the +# directive. +# +# Change this to Listen on specific IP addresses as shown below to +# prevent Apache from glomming onto all bound IP addresses. +# +#Listen 12.34.56.78:80 +Listen 80 + +# +# Dynamic Shared Object (DSO) Support +# +# To be able to use the functionality of a module which was built as a DSO you +# have to place corresponding `LoadModule' lines at this location so the +# directives contained in it are actually available _before_ they are used. +# Statically compiled modules (those listed by `httpd -l') do not need +# to be loaded here. +# +# Example: +# LoadModule foo_module modules/mod_foo.so +# +LoadModule mpm_event_module modules/mod_mpm_event.so +#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so +#LoadModule mpm_worker_module modules/mod_mpm_worker.so +LoadModule authn_file_module modules/mod_authn_file.so +#LoadModule authn_dbm_module modules/mod_authn_dbm.so +#LoadModule authn_anon_module modules/mod_authn_anon.so +#LoadModule authn_dbd_module modules/mod_authn_dbd.so +#LoadModule authn_socache_module modules/mod_authn_socache.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authz_host_module modules/mod_authz_host.so +LoadModule authz_groupfile_module modules/mod_authz_groupfile.so +LoadModule authz_user_module modules/mod_authz_user.so +#LoadModule authz_dbm_module modules/mod_authz_dbm.so +#LoadModule authz_owner_module modules/mod_authz_owner.so +#LoadModule authz_dbd_module modules/mod_authz_dbd.so +LoadModule authz_core_module modules/mod_authz_core.so +#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so +#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so +LoadModule access_compat_module modules/mod_access_compat.so +LoadModule auth_basic_module modules/mod_auth_basic.so +#LoadModule auth_form_module modules/mod_auth_form.so +#LoadModule auth_digest_module modules/mod_auth_digest.so +#LoadModule allowmethods_module modules/mod_allowmethods.so +#LoadModule isapi_module modules/mod_isapi.so +#LoadModule file_cache_module modules/mod_file_cache.so +#LoadModule cache_module modules/mod_cache.so +#LoadModule cache_disk_module modules/mod_cache_disk.so +#LoadModule cache_socache_module modules/mod_cache_socache.so +#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so +#LoadModule socache_dbm_module modules/mod_socache_dbm.so +#LoadModule socache_memcache_module modules/mod_socache_memcache.so +#LoadModule socache_redis_module modules/mod_socache_redis.so +#LoadModule watchdog_module modules/mod_watchdog.so +#LoadModule macro_module modules/mod_macro.so +#LoadModule dbd_module modules/mod_dbd.so +#LoadModule bucketeer_module modules/mod_bucketeer.so +#LoadModule dumpio_module modules/mod_dumpio.so +#LoadModule echo_module modules/mod_echo.so +#LoadModule example_hooks_module modules/mod_example_hooks.so +#LoadModule case_filter_module modules/mod_case_filter.so +#LoadModule case_filter_in_module modules/mod_case_filter_in.so +#LoadModule example_ipc_module modules/mod_example_ipc.so +#LoadModule buffer_module modules/mod_buffer.so +#LoadModule data_module modules/mod_data.so +#LoadModule ratelimit_module modules/mod_ratelimit.so +LoadModule reqtimeout_module modules/mod_reqtimeout.so +#LoadModule ext_filter_module modules/mod_ext_filter.so +#LoadModule request_module modules/mod_request.so +#LoadModule include_module modules/mod_include.so +LoadModule filter_module modules/mod_filter.so +#LoadModule reflector_module modules/mod_reflector.so +#LoadModule substitute_module modules/mod_substitute.so +#LoadModule sed_module modules/mod_sed.so +#LoadModule charset_lite_module modules/mod_charset_lite.so +#LoadModule deflate_module modules/mod_deflate.so +#LoadModule xml2enc_module modules/mod_xml2enc.so +#LoadModule proxy_html_module modules/mod_proxy_html.so +#LoadModule brotli_module modules/mod_brotli.so +LoadModule mime_module modules/mod_mime.so +#LoadModule ldap_module modules/mod_ldap.so +LoadModule log_config_module modules/mod_log_config.so +#LoadModule log_debug_module modules/mod_log_debug.so +#LoadModule log_forensic_module modules/mod_log_forensic.so +#LoadModule logio_module modules/mod_logio.so +#LoadModule lua_module modules/mod_lua.so +LoadModule env_module modules/mod_env.so +#LoadModule mime_magic_module modules/mod_mime_magic.so +#LoadModule cern_meta_module modules/mod_cern_meta.so +#LoadModule expires_module modules/mod_expires.so +LoadModule headers_module modules/mod_headers.so +#LoadModule ident_module modules/mod_ident.so +#LoadModule usertrack_module modules/mod_usertrack.so +#LoadModule unique_id_module modules/mod_unique_id.so +LoadModule setenvif_module modules/mod_setenvif.so +LoadModule version_module modules/mod_version.so +#LoadModule remoteip_module modules/mod_remoteip.so +#LoadModule proxy_module modules/mod_proxy.so +#LoadModule proxy_connect_module modules/mod_proxy_connect.so +#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so +#LoadModule proxy_http_module modules/mod_proxy_http.so +#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so +#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so +#LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so +#LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so +#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so +#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so +#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so +#LoadModule proxy_express_module modules/mod_proxy_express.so +#LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so +#LoadModule session_module modules/mod_session.so +#LoadModule session_cookie_module modules/mod_session_cookie.so +#LoadModule session_crypto_module modules/mod_session_crypto.so +#LoadModule session_dbd_module modules/mod_session_dbd.so +#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so +#LoadModule slotmem_plain_module modules/mod_slotmem_plain.so +#LoadModule ssl_module modules/mod_ssl.so +#LoadModule optional_hook_export_module modules/mod_optional_hook_export.so +#LoadModule optional_hook_import_module modules/mod_optional_hook_import.so +#LoadModule optional_fn_import_module modules/mod_optional_fn_import.so +#LoadModule optional_fn_export_module modules/mod_optional_fn_export.so +#LoadModule dialup_module modules/mod_dialup.so +#LoadModule http2_module modules/mod_http2.so +#LoadModule proxy_http2_module modules/mod_proxy_http2.so +#LoadModule md_module modules/mod_md.so +#LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so +#LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so +#LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so +#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so +LoadModule unixd_module modules/mod_unixd.so +#LoadModule heartbeat_module modules/mod_heartbeat.so +#LoadModule heartmonitor_module modules/mod_heartmonitor.so +#LoadModule dav_module modules/mod_dav.so +LoadModule status_module modules/mod_status.so +LoadModule autoindex_module modules/mod_autoindex.so +#LoadModule asis_module modules/mod_asis.so +#LoadModule info_module modules/mod_info.so +#LoadModule suexec_module modules/mod_suexec.so + + #LoadModule cgid_module modules/mod_cgid.so + + + #LoadModule cgi_module modules/mod_cgi.so + +#LoadModule dav_fs_module modules/mod_dav_fs.so +#LoadModule dav_lock_module modules/mod_dav_lock.so +#LoadModule vhost_alias_module modules/mod_vhost_alias.so +#LoadModule negotiation_module modules/mod_negotiation.so +LoadModule dir_module modules/mod_dir.so +#LoadModule imagemap_module modules/mod_imagemap.so +#LoadModule actions_module modules/mod_actions.so +#LoadModule speling_module modules/mod_speling.so +#LoadModule userdir_module modules/mod_userdir.so +LoadModule alias_module modules/mod_alias.so +#LoadModule rewrite_module modules/mod_rewrite.so + + +# +# If you wish httpd to run as a different user or group, you must run +# httpd as root initially and it will switch. +# +# User/Group: The name (or #number) of the user/group to run httpd as. +# It is usually good practice to create a dedicated user and group for +# running httpd, as with most system services. +# +User www-data +Group www-data + + + +# 'Main' server configuration +# +# The directives in this section set up the values used by the 'main' +# server, which responds to any requests that aren't handled by a +# definition. These values also provide defaults for +# any containers you may define later in the file. +# +# All of these directives may appear inside containers, +# in which case these default settings will be overridden for the +# virtual host being defined. +# + +# +# ServerAdmin: Your address, where problems with the server should be +# e-mailed. This address appears on some server-generated pages, such +# as error documents. e.g. admin@your-domain.com +# +ServerAdmin you@example.com + +# +# ServerName gives the name and port that the server uses to identify itself. +# This can often be determined automatically, but we recommend you specify +# it explicitly to prevent problems during startup. +# +# If your host doesn't have a registered DNS name, enter its IP address here. +# +#ServerName www.example.com:80 + +# +# Deny access to the entirety of your server's filesystem. You must +# explicitly permit access to web content directories in other +# blocks below. +# + + AllowOverride none + Require all denied + + +# +# Note that from this point forward you must specifically allow +# particular features to be enabled - so if something's not working as +# you might expect, make sure that you have specifically enabled it +# below. +# + +# +# DocumentRoot: The directory out of which you will serve your +# documents. By default, all requests are taken from this directory, but +# symbolic links and aliases may be used to point to other locations. +# +DocumentRoot "/usr/local/apache2/htdocs" + + # + # Possible values for the Options directive are "None", "All", + # or any combination of: + # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews + # + # Note that "MultiViews" must be named *explicitly* --- "Options All" + # doesn't give it to you. + # + # The Options directive is both complicated and important. Please see + # http://httpd.apache.org/docs/2.4/mod/core.html#options + # for more information. + # + Options Indexes FollowSymLinks + + # + # AllowOverride controls what directives may be placed in .htaccess files. + # It can be "All", "None", or any combination of the keywords: + # AllowOverride FileInfo AuthConfig Limit + # + AllowOverride None + + # + # Controls who can get stuff from this server. + # + Require all granted + + +# +# DirectoryIndex: sets the file that Apache will serve if a directory +# is requested. +# + + DirectoryIndex index.html + + +# +# The following lines prevent .htaccess and .htpasswd files from being +# viewed by Web clients. +# + + Require all denied + + +# +# ErrorLog: The location of the error log file. +# If you do not specify an ErrorLog directive within a +# container, error messages relating to that virtual host will be +# logged here. If you *do* define an error logfile for a +# container, that host's errors will be logged there and not here. +# +ErrorLog /proc/self/fd/2 + +# +# LogLevel: Control the number of messages logged to the error_log. +# Possible values include: debug, info, notice, warn, error, crit, +# alert, emerg. +# +LogLevel warn + + + # + # The following directives define some format nicknames for use with + # a CustomLog directive (see below). + # + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + + # You need to enable mod_logio.c to use %I and %O + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + + # + # The location and format of the access logfile (Common Logfile Format). + # If you do not define any access logfiles within a + # container, they will be logged here. Contrariwise, if you *do* + # define per- access logfiles, transactions will be + # logged therein and *not* in this file. + # + CustomLog /proc/self/fd/1 common + + # + # If you prefer a logfile with access, agent, and referer information + # (Combined Logfile Format) you can use the following directive. + # + #CustomLog "logs/access_log" combined + + + + # + # Redirect: Allows you to tell clients about documents that used to + # exist in your server's namespace, but do not anymore. The client + # will make a new request for the document at its new location. + # Example: + # Redirect permanent /foo http://www.example.com/bar + + # + # Alias: Maps web paths into filesystem paths and is used to + # access content that does not live under the DocumentRoot. + # Example: + # Alias /webpath /full/filesystem/path + # + # If you include a trailing / on /webpath then the server will + # require it to be present in the URL. You will also likely + # need to provide a section to allow access to + # the filesystem path. + + # + # ScriptAlias: This controls which directories contain server scripts. + # ScriptAliases are essentially the same as Aliases, except that + # documents in the target directory are treated as applications and + # run by the server when requested rather than as documents sent to the + # client. The same rules about trailing "/" apply to ScriptAlias + # directives as to Alias. + # + ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/" + + + + + # + # ScriptSock: On threaded servers, designate the path to the UNIX + # socket used to communicate with the CGI daemon of mod_cgid. + # + #Scriptsock cgisock + + +# +# "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased +# CGI directory exists, if you have that configured. +# + + AllowOverride None + Options None + Require all granted + + + + # + # Avoid passing HTTP_PROXY environment to CGI's on this or any proxied + # backend servers which have lingering "httpoxy" defects. + # 'Proxy' request header is undefined by the IETF, not listed by IANA + # + RequestHeader unset Proxy early + + + + # + # TypesConfig points to the file containing the list of mappings from + # filename extension to MIME-type. + # + TypesConfig conf/mime.types + + # + # AddType allows you to add to or override the MIME configuration + # file specified in TypesConfig for specific file types. + # + #AddType application/x-gzip .tgz + # + # AddEncoding allows you to have certain browsers uncompress + # information on the fly. Note: Not all browsers support this. + # + #AddEncoding x-compress .Z + #AddEncoding x-gzip .gz .tgz + # + # If the AddEncoding directives above are commented-out, then you + # probably should define those extensions to indicate media types: + # + AddType application/x-compress .Z + AddType application/x-gzip .gz .tgz + + # + # AddHandler allows you to map certain file extensions to "handlers": + # actions unrelated to filetype. These can be either built into the server + # or added with the Action directive (see below) + # + # To use CGI scripts outside of ScriptAliased directories: + # (You will also need to add "ExecCGI" to the "Options" directive.) + # + #AddHandler cgi-script .cgi + + # For type maps (negotiated resources): + #AddHandler type-map var + + # + # Filters allow you to process content before it is sent to the client. + # + # To parse .shtml files for server-side includes (SSI): + # (You will also need to add "Includes" to the "Options" directive.) + # + #AddType text/html .shtml + #AddOutputFilter INCLUDES .shtml + + +# +# The mod_mime_magic module allows the server to use various hints from the +# contents of the file itself to determine its type. The MIMEMagicFile +# directive tells the module where the hint definitions are located. +# +#MIMEMagicFile conf/magic + +# +# Customizable error responses come in three flavors: +# 1) plain text 2) local redirects 3) external redirects +# +# Some examples: +#ErrorDocument 500 "The server made a boo boo." +#ErrorDocument 404 /missing.html +#ErrorDocument 404 "/cgi-bin/missing_handler.pl" +#ErrorDocument 402 http://www.example.com/subscription_info.html +# + +# +# MaxRanges: Maximum number of Ranges in a request before +# returning the entire resource, or one of the special +# values 'default', 'none' or 'unlimited'. +# Default setting is to accept 200 Ranges. +#MaxRanges unlimited + +# +# EnableMMAP and EnableSendfile: On systems that support it, +# memory-mapping or the sendfile syscall may be used to deliver +# files. This usually improves server performance, but must +# be turned off when serving from networked-mounted +# filesystems or if support for these functions is otherwise +# broken on your system. +# Defaults: EnableMMAP On, EnableSendfile Off +# +#EnableMMAP off +#EnableSendfile on + +# Supplemental configuration +# +# The configuration files in the conf/extra/ directory can be +# included to add extra features or to modify the default configuration of +# the server, or you may simply copy their contents here and change as +# necessary. + +# Server-pool management (MPM specific) +#Include conf/extra/httpd-mpm.conf + +# Multi-language error messages +#Include conf/extra/httpd-multilang-errordoc.conf + +# Fancy directory listings +#Include conf/extra/httpd-autoindex.conf + +# Language settings +#Include conf/extra/httpd-languages.conf + +# User home directories +#Include conf/extra/httpd-userdir.conf + +# Real-time info on requests and configuration +#Include conf/extra/httpd-info.conf + +# Virtual hosts +#Include conf/extra/httpd-vhosts.conf + +# Local access to the Apache HTTP Server Manual +#Include conf/extra/httpd-manual.conf + +# Distributed authoring and versioning (WebDAV) +#Include conf/extra/httpd-dav.conf + +# Various default settings +#Include conf/extra/httpd-default.conf + +# Configure mod_proxy_html to understand HTML4/XHTML1 + +Include conf/extra/proxy-html.conf + + +# Secure (SSL/TLS) connections +#Include conf/extra/httpd-ssl.conf +# +# Note: The following must must be present to support +# starting without SSL on platforms with no /dev/random equivalent +# but a statically compiled-in mod_ssl. +# + +SSLRandomSeed startup builtin +SSLRandomSeed connect builtin + + diff --git a/tests/proxy/httpd_proxypass.conf b/tests/proxy/httpd_proxypass.conf new file mode 100644 index 00000000..ba7bd4bf --- /dev/null +++ b/tests/proxy/httpd_proxypass.conf @@ -0,0 +1,577 @@ +# +# This is the main Apache HTTP server configuration file. It contains the +# configuration directives that give the server its instructions. +# See for detailed information. +# In particular, see +# +# for a discussion of each configuration directive. +# +# Do NOT simply read the instructions in here without understanding +# what they do. They're here only as hints or reminders. If you are unsure +# consult the online docs. You have been warned. +# +# Configuration and logfile names: If the filenames you specify for many +# of the server's control files begin with "/" (or "drive:/" for Win32), the +# server will use that explicit path. If the filenames do *not* begin +# with "/", the value of ServerRoot is prepended -- so "logs/access_log" +# with ServerRoot set to "/usr/local/apache2" will be interpreted by the +# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log" +# will be interpreted as '/logs/access_log'. + +# +# ServerRoot: The top of the directory tree under which the server's +# configuration, error, and log files are kept. +# +# Do not add a slash at the end of the directory path. If you point +# ServerRoot at a non-local disk, be sure to specify a local disk on the +# Mutex directive, if file-based mutexes are used. If you wish to share the +# same ServerRoot for multiple httpd daemons, you will need to change at +# least PidFile. +# +ServerRoot "/usr/local/apache2" + +# +# Mutex: Allows you to set the mutex mechanism and mutex file directory +# for individual mutexes, or change the global defaults +# +# Uncomment and change the directory if mutexes are file-based and the default +# mutex file directory is not on a local disk or is not appropriate for some +# other reason. +# +# Mutex default:logs + +# +# Listen: Allows you to bind Apache to specific IP addresses and/or +# ports, instead of the default. See also the +# directive. +# +# Change this to Listen on specific IP addresses as shown below to +# prevent Apache from glomming onto all bound IP addresses. +# +#Listen 12.34.56.78:80 +Listen 8808 + +# +# Dynamic Shared Object (DSO) Support +# +# To be able to use the functionality of a module which was built as a DSO you +# have to place corresponding `LoadModule' lines at this location so the +# directives contained in it are actually available _before_ they are used. +# Statically compiled modules (those listed by `httpd -l') do not need +# to be loaded here. +# +# Example: +# LoadModule foo_module modules/mod_foo.so +# +LoadModule mpm_event_module modules/mod_mpm_event.so +#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so +#LoadModule mpm_worker_module modules/mod_mpm_worker.so +LoadModule authn_file_module modules/mod_authn_file.so +#LoadModule authn_dbm_module modules/mod_authn_dbm.so +#LoadModule authn_anon_module modules/mod_authn_anon.so +#LoadModule authn_dbd_module modules/mod_authn_dbd.so +#LoadModule authn_socache_module modules/mod_authn_socache.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authz_host_module modules/mod_authz_host.so +LoadModule authz_groupfile_module modules/mod_authz_groupfile.so +LoadModule authz_user_module modules/mod_authz_user.so +#LoadModule authz_dbm_module modules/mod_authz_dbm.so +#LoadModule authz_owner_module modules/mod_authz_owner.so +#LoadModule authz_dbd_module modules/mod_authz_dbd.so +LoadModule authz_core_module modules/mod_authz_core.so +#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so +#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so +LoadModule access_compat_module modules/mod_access_compat.so +LoadModule auth_basic_module modules/mod_auth_basic.so +#LoadModule auth_form_module modules/mod_auth_form.so +#LoadModule auth_digest_module modules/mod_auth_digest.so +#LoadModule allowmethods_module modules/mod_allowmethods.so +#LoadModule isapi_module modules/mod_isapi.so +#LoadModule file_cache_module modules/mod_file_cache.so +#LoadModule cache_module modules/mod_cache.so +#LoadModule cache_disk_module modules/mod_cache_disk.so +#LoadModule cache_socache_module modules/mod_cache_socache.so +#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so +#LoadModule socache_dbm_module modules/mod_socache_dbm.so +#LoadModule socache_memcache_module modules/mod_socache_memcache.so +#LoadModule socache_redis_module modules/mod_socache_redis.so +#LoadModule watchdog_module modules/mod_watchdog.so +#LoadModule macro_module modules/mod_macro.so +#LoadModule dbd_module modules/mod_dbd.so +#LoadModule bucketeer_module modules/mod_bucketeer.so +#LoadModule dumpio_module modules/mod_dumpio.so +#LoadModule echo_module modules/mod_echo.so +#LoadModule example_hooks_module modules/mod_example_hooks.so +#LoadModule case_filter_module modules/mod_case_filter.so +#LoadModule case_filter_in_module modules/mod_case_filter_in.so +#LoadModule example_ipc_module modules/mod_example_ipc.so +#LoadModule buffer_module modules/mod_buffer.so +#LoadModule data_module modules/mod_data.so +#LoadModule ratelimit_module modules/mod_ratelimit.so +LoadModule reqtimeout_module modules/mod_reqtimeout.so +#LoadModule ext_filter_module modules/mod_ext_filter.so +#LoadModule request_module modules/mod_request.so +#LoadModule include_module modules/mod_include.so +LoadModule filter_module modules/mod_filter.so +#LoadModule reflector_module modules/mod_reflector.so +#LoadModule substitute_module modules/mod_substitute.so +#LoadModule sed_module modules/mod_sed.so +#LoadModule charset_lite_module modules/mod_charset_lite.so +#LoadModule deflate_module modules/mod_deflate.so +#LoadModule xml2enc_module modules/mod_xml2enc.so +#LoadModule proxy_html_module modules/mod_proxy_html.so +#LoadModule brotli_module modules/mod_brotli.so +LoadModule mime_module modules/mod_mime.so +#LoadModule ldap_module modules/mod_ldap.so +LoadModule log_config_module modules/mod_log_config.so +#LoadModule log_debug_module modules/mod_log_debug.so +#LoadModule log_forensic_module modules/mod_log_forensic.so +#LoadModule logio_module modules/mod_logio.so +#LoadModule lua_module modules/mod_lua.so +LoadModule env_module modules/mod_env.so +#LoadModule mime_magic_module modules/mod_mime_magic.so +#LoadModule cern_meta_module modules/mod_cern_meta.so +#LoadModule expires_module modules/mod_expires.so +LoadModule headers_module modules/mod_headers.so +#LoadModule ident_module modules/mod_ident.so +#LoadModule usertrack_module modules/mod_usertrack.so +#LoadModule unique_id_module modules/mod_unique_id.so +LoadModule setenvif_module modules/mod_setenvif.so +LoadModule version_module modules/mod_version.so +#LoadModule remoteip_module modules/mod_remoteip.so +LoadModule proxy_module modules/mod_proxy.so +#LoadModule proxy_connect_module modules/mod_proxy_connect.so +#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so +LoadModule proxy_http_module modules/mod_proxy_http.so +#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so +#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so +#LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so +#LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so +#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so +#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so +#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so +#LoadModule proxy_express_module modules/mod_proxy_express.so +#LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so +#LoadModule session_module modules/mod_session.so +#LoadModule session_cookie_module modules/mod_session_cookie.so +#LoadModule session_crypto_module modules/mod_session_crypto.so +#LoadModule session_dbd_module modules/mod_session_dbd.so +#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so +#LoadModule slotmem_plain_module modules/mod_slotmem_plain.so +LoadModule ssl_module modules/mod_ssl.so +#LoadModule optional_hook_export_module modules/mod_optional_hook_export.so +#LoadModule optional_hook_import_module modules/mod_optional_hook_import.so +#LoadModule optional_fn_import_module modules/mod_optional_fn_import.so +#LoadModule optional_fn_export_module modules/mod_optional_fn_export.so +#LoadModule dialup_module modules/mod_dialup.so +#LoadModule http2_module modules/mod_http2.so +#LoadModule proxy_http2_module modules/mod_proxy_http2.so +#LoadModule md_module modules/mod_md.so +#LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so +#LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so +#LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so +#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so +LoadModule unixd_module modules/mod_unixd.so +#LoadModule heartbeat_module modules/mod_heartbeat.so +#LoadModule heartmonitor_module modules/mod_heartmonitor.so +#LoadModule dav_module modules/mod_dav.so +LoadModule status_module modules/mod_status.so +LoadModule autoindex_module modules/mod_autoindex.so +#LoadModule asis_module modules/mod_asis.so +#LoadModule info_module modules/mod_info.so +#LoadModule suexec_module modules/mod_suexec.so + + #LoadModule cgid_module modules/mod_cgid.so + + + #LoadModule cgi_module modules/mod_cgi.so + +#LoadModule dav_fs_module modules/mod_dav_fs.so +#LoadModule dav_lock_module modules/mod_dav_lock.so +#LoadModule vhost_alias_module modules/mod_vhost_alias.so +#LoadModule negotiation_module modules/mod_negotiation.so +LoadModule dir_module modules/mod_dir.so +#LoadModule imagemap_module modules/mod_imagemap.so +#LoadModule actions_module modules/mod_actions.so +#LoadModule speling_module modules/mod_speling.so +#LoadModule userdir_module modules/mod_userdir.so +LoadModule alias_module modules/mod_alias.so +#LoadModule rewrite_module modules/mod_rewrite.so + + +# +# If you wish httpd to run as a different user or group, you must run +# httpd as root initially and it will switch. +# +# User/Group: The name (or #number) of the user/group to run httpd as. +# It is usually good practice to create a dedicated user and group for +# running httpd, as with most system services. +# +User www-data +Group www-data + + + +# 'Main' server configuration +# +# The directives in this section set up the values used by the 'main' +# server, which responds to any requests that aren't handled by a +# definition. These values also provide defaults for +# any containers you may define later in the file. +# +# All of these directives may appear inside containers, +# in which case these default settings will be overridden for the +# virtual host being defined. +# + +# +# ServerAdmin: Your address, where problems with the server should be +# e-mailed. This address appears on some server-generated pages, such +# as error documents. e.g. admin@your-domain.com +# +ServerAdmin you@example.com + +# +# ServerName gives the name and port that the server uses to identify itself. +# This can often be determined automatically, but we recommend you specify +# it explicitly to prevent problems during startup. +# +# If your host doesn't have a registered DNS name, enter its IP address here. +# +#ServerName www.example.com:80 + +# +# Deny access to the entirety of your server's filesystem. You must +# explicitly permit access to web content directories in other +# blocks below. +# + + AllowOverride none + Require all denied + + +# +# Note that from this point forward you must specifically allow +# particular features to be enabled - so if something's not working as +# you might expect, make sure that you have specifically enabled it +# below. +# + +# +# DocumentRoot: The directory out of which you will serve your +# documents. By default, all requests are taken from this directory, but +# symbolic links and aliases may be used to point to other locations. +# +DocumentRoot "/usr/local/apache2/htdocs" + + # + # Possible values for the Options directive are "None", "All", + # or any combination of: + # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews + # + # Note that "MultiViews" must be named *explicitly* --- "Options All" + # doesn't give it to you. + # + # The Options directive is both complicated and important. Please see + # http://httpd.apache.org/docs/2.4/mod/core.html#options + # for more information. + # + Options Indexes FollowSymLinks + + # + # AllowOverride controls what directives may be placed in .htaccess files. + # It can be "All", "None", or any combination of the keywords: + # AllowOverride FileInfo AuthConfig Limit + # + AllowOverride None + + # + # Controls who can get stuff from this server. + # + Require all granted + + +# +# DirectoryIndex: sets the file that Apache will serve if a directory +# is requested. +# + + DirectoryIndex index.html + + +# +# The following lines prevent .htaccess and .htpasswd files from being +# viewed by Web clients. +# + + Require all denied + + +# +# ErrorLog: The location of the error log file. +# If you do not specify an ErrorLog directive within a +# container, error messages relating to that virtual host will be +# logged here. If you *do* define an error logfile for a +# container, that host's errors will be logged there and not here. +# +ErrorLog /proc/self/fd/2 + +# +# LogLevel: Control the number of messages logged to the error_log. +# Possible values include: debug, info, notice, warn, error, crit, +# alert, emerg. +# +LogLevel warn + + + # + # The following directives define some format nicknames for use with + # a CustomLog directive (see below). + # + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + + # You need to enable mod_logio.c to use %I and %O + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + + # + # The location and format of the access logfile (Common Logfile Format). + # If you do not define any access logfiles within a + # container, they will be logged here. Contrariwise, if you *do* + # define per- access logfiles, transactions will be + # logged therein and *not* in this file. + # + CustomLog /proc/self/fd/1 common + + # + # If you prefer a logfile with access, agent, and referer information + # (Combined Logfile Format) you can use the following directive. + # + #CustomLog "logs/access_log" combined + + + + # + # Redirect: Allows you to tell clients about documents that used to + # exist in your server's namespace, but do not anymore. The client + # will make a new request for the document at its new location. + # Example: + # Redirect permanent /foo http://www.example.com/bar + + # + # Alias: Maps web paths into filesystem paths and is used to + # access content that does not live under the DocumentRoot. + # Example: + # Alias /webpath /full/filesystem/path + # + # If you include a trailing / on /webpath then the server will + # require it to be present in the URL. You will also likely + # need to provide a section to allow access to + # the filesystem path. + + # + # ScriptAlias: This controls which directories contain server scripts. + # ScriptAliases are essentially the same as Aliases, except that + # documents in the target directory are treated as applications and + # run by the server when requested rather than as documents sent to the + # client. The same rules about trailing "/" apply to ScriptAlias + # directives as to Alias. + # + ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/" + + + + + # + # ScriptSock: On threaded servers, designate the path to the UNIX + # socket used to communicate with the CGI daemon of mod_cgid. + # + #Scriptsock cgisock + + +# +# "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased +# CGI directory exists, if you have that configured. +# + + AllowOverride None + Options None + Require all granted + + + + # + # Avoid passing HTTP_PROXY environment to CGI's on this or any proxied + # backend servers which have lingering "httpoxy" defects. + # 'Proxy' request header is undefined by the IETF, not listed by IANA + # + RequestHeader unset Proxy early + + + + # + # TypesConfig points to the file containing the list of mappings from + # filename extension to MIME-type. + # + TypesConfig conf/mime.types + + # + # AddType allows you to add to or override the MIME configuration + # file specified in TypesConfig for specific file types. + # + #AddType application/x-gzip .tgz + # + # AddEncoding allows you to have certain browsers uncompress + # information on the fly. Note: Not all browsers support this. + # + #AddEncoding x-compress .Z + #AddEncoding x-gzip .gz .tgz + # + # If the AddEncoding directives above are commented-out, then you + # probably should define those extensions to indicate media types: + # + AddType application/x-compress .Z + AddType application/x-gzip .gz .tgz + + # + # AddHandler allows you to map certain file extensions to "handlers": + # actions unrelated to filetype. These can be either built into the server + # or added with the Action directive (see below) + # + # To use CGI scripts outside of ScriptAliased directories: + # (You will also need to add "ExecCGI" to the "Options" directive.) + # + #AddHandler cgi-script .cgi + + # For type maps (negotiated resources): + #AddHandler type-map var + + # + # Filters allow you to process content before it is sent to the client. + # + # To parse .shtml files for server-side includes (SSI): + # (You will also need to add "Includes" to the "Options" directive.) + # + #AddType text/html .shtml + #AddOutputFilter INCLUDES .shtml + + +# +# The mod_mime_magic module allows the server to use various hints from the +# contents of the file itself to determine its type. The MIMEMagicFile +# directive tells the module where the hint definitions are located. +# +#MIMEMagicFile conf/magic + +# +# Customizable error responses come in three flavors: +# 1) plain text 2) local redirects 3) external redirects +# +# Some examples: +#ErrorDocument 500 "The server made a boo boo." +#ErrorDocument 404 /missing.html +#ErrorDocument 404 "/cgi-bin/missing_handler.pl" +#ErrorDocument 402 http://www.example.com/subscription_info.html +# + +# +# MaxRanges: Maximum number of Ranges in a request before +# returning the entire resource, or one of the special +# values 'default', 'none' or 'unlimited'. +# Default setting is to accept 200 Ranges. +#MaxRanges unlimited + +# +# EnableMMAP and EnableSendfile: On systems that support it, +# memory-mapping or the sendfile syscall may be used to deliver +# files. This usually improves server performance, but must +# be turned off when serving from networked-mounted +# filesystems or if support for these functions is otherwise +# broken on your system. +# Defaults: EnableMMAP On, EnableSendfile Off +# +#EnableMMAP off +#EnableSendfile on + +# Supplemental configuration +# +# The configuration files in the conf/extra/ directory can be +# included to add extra features or to modify the default configuration of +# the server, or you may simply copy their contents here and change as +# necessary. + +# Server-pool management (MPM specific) +#Include conf/extra/httpd-mpm.conf + +# Multi-language error messages +#Include conf/extra/httpd-multilang-errordoc.conf + +# Fancy directory listings +#Include conf/extra/httpd-autoindex.conf + +# Language settings +#Include conf/extra/httpd-languages.conf + +# User home directories +#Include conf/extra/httpd-userdir.conf + +# Real-time info on requests and configuration +#Include conf/extra/httpd-info.conf + +# Virtual hosts +#Include conf/extra/httpd-vhosts.conf + +# Local access to the Apache HTTP Server Manual +#Include conf/extra/httpd-manual.conf + +# Distributed authoring and versioning (WebDAV) +#Include conf/extra/httpd-dav.conf + +# Various default settings +#Include conf/extra/httpd-default.conf + +# Configure mod_proxy_html to understand HTML4/XHTML1 + +Include conf/extra/proxy-html.conf + + +# Secure (SSL/TLS) connections +#Include conf/extra/httpd-ssl.conf +# +# Note: The following must must be present to support +# starting without SSL on platforms with no /dev/random equivalent +# but a statically compiled-in mod_ssl. +# + +SSLRandomSeed startup builtin +SSLRandomSeed connect builtin + + +# Global config + +SSLProxyEngine on +# all external accesses should go through this proxy (this is my local squid) +# PLACE YOUR OPENSHIFT PROXY HERE - the one that is defined by the https_proxy variable +ProxyRemote * http://pdm-00781:3128 + +NameVirtualHost * + + ServerName owncloud.mydomain.com + + ProxyRequests Off + + Order deny,allow + Allow from all + + + # pass everything to https://fgt-dev.pharmaledger.pdmfc.com + # use https://fgt.pharmaledger.pdmfc.com when confident + ProxyPass / https://fgt-dev.pharmaledger.pdmfc.com/ + ProxyPassReverse / https://fgt-dev.pharmaledger.pdmfc.com/ + + Order allow,deny + Allow from all + + From aef89d32f8db17a355cb48b87ac8b6cc2dca42fa Mon Sep 17 00:00:00 2001 From: jpsl Date: Sat, 22 Oct 2022 19:27:33 +0100 Subject: [PATCH 9/9] #122 - fix master merge mistake --- apihub-root/external-volume/config/bdns.hosts | 6 +++--- fgt-api/config/fgt-mah-wallet/credentials.json | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apihub-root/external-volume/config/bdns.hosts b/apihub-root/external-volume/config/bdns.hosts index f9711e63..f8bcebe9 100644 --- a/apihub-root/external-volume/config/bdns.hosts +++ b/apihub-root/external-volume/config/bdns.hosts @@ -11,13 +11,13 @@ "traceability": { "replicas": [], "brickStorages": [ - "http://localhost:8808" + "$ORIGIN" ], "mqEndpoints": [ - "http://localhost:8808" + "$ORIGIN" ], "anchoringServices": [ - "http://localhost:8808" + "$ORIGIN" ] }, "epi": { diff --git a/fgt-api/config/fgt-mah-wallet/credentials.json b/fgt-api/config/fgt-mah-wallet/credentials.json index b83ff881..41abaebb 100644 --- a/fgt-api/config/fgt-mah-wallet/credentials.json +++ b/fgt-api/config/fgt-mah-wallet/credentials.json @@ -1,14 +1,14 @@ { "name": { - "secret": "PDM-JPSL", + "secret": "F. Hoffmann-La Roche AG", "public": true }, "id": { - "secret": "MAH-PDM-JPSL", + "secret": "MAH116267986", "public": true }, "email": { - "secret": "pdm-jpsl@mah.pharmaledger.com", + "secret": "roche@mah.pharmaledger.com", "public": true }, "address": { @@ -22,4 +22,4 @@ "required": true, "secret": "This1sSuchAS3curePassw0rd" } - } \ No newline at end of file + }