diff --git a/p/ivb/base.json b/p/ivb/base.json new file mode 100644 index 00000000..55957906 --- /dev/null +++ b/p/ivb/base.json @@ -0,0 +1,13 @@ +{ + "auth": { + "type": "AID", + "aid": "wf7mcf9bv3nv8g5f" + }, + "client": { + "type": "WEB", + "id": "VAO", + "name": "webapp" + }, + "endpoint": "https://fahrplan.ivb.at/bin/mgate.exe", + "defaultLanguage": "de" +} diff --git a/p/ivb/digicert-tls-rsa-sha256-2020-ca1.crt.pem b/p/ivb/digicert-tls-rsa-sha256-2020-ca1.crt.pem new file mode 100644 index 00000000..3582b754 --- /dev/null +++ b/p/ivb/digicert-tls-rsa-sha256-2020-ca1.crt.pem @@ -0,0 +1,6 @@ +-----BEGIN CERTIFICATE----- +MIIE6jCCA9KgAwIBAgIQCjUI1VwpKwF9+K1lwA/35DANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0yMDA5MjQwMDAwMDBaFw0zMDA5MjMyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBSU0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6aqXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddng9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuWraKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGBAfr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21reacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBrjCCAaowHQYDVR0OBBYEFLdrouqoqoSMeeq02g+YssWVdrn0MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDAGA1UdIAQpMCcwBwYFZ4EMAQEwCAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEBAHert3onPa679n/gWlbJhKrKW3EX3SJH/E6f7tDBpATho+vFScH90cnfjK+URSxGKqNjOSD5nkoklEHIqdninFQFBstcHL4AGw+oWv8Zu2XHFq8hVt1hBcnpj5h232sb0HIMULkwKXq/YFkQZhM6LawVEWwtIwwCPgU7/uWhnOKK24fXSuhe50gG66sSmvKvhMNbg0qZgYOrAKHKCjxMoiWJKiKnpPMzTFuMLhoClw+dj20tlQj7T9rxkTgl4ZxuYRiHas6xuwAwapu3r9rxxZf+ingkquqTgLozZXq8oXfpf2kUCwA/d5KxTVtzhwoT0JzI8ks5T1KESaZMkE4f97Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQkCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- diff --git a/p/ivb/example.js b/p/ivb/example.js new file mode 100644 index 00000000..4e10e7ad --- /dev/null +++ b/p/ivb/example.js @@ -0,0 +1,49 @@ +'use strict' + +const createClient = require('../..') +const ivbProfile = require('.') + +const client = createClient(ivbProfile, 'hafas-client example') + +const innsbruckGriesauweg = '476162400' +const völsWest = '476431800' + +// client.journeys(innsbruckGriesauweg, völsWest, { +// results: 1, stopovers: true, +// }) +// .then(({journeys}) => { +// const [journey] = journeys +// return client.refreshJourney(journey.refreshToken, {stopovers: true, remarks: true}) +// }) +// .then(({journeys}) => { +// const [journey] = journeys +// const leg = journey.legs[0] +// return client.trip(leg.tripId, leg.line.name, {polyline: true}) +// }) + +// client.departures(innsbruckGriesauweg, {duration: 1}) +// client.arrivals(innsbruckGriesauweg, {duration: 10, linesOfStops: true}) + +client.locations('griesauweg', {results: 3}) +// client.stop(innsbruckGriesauweg, {linesOfStops: true}) +// client.nearby({ +// type: 'location', +// id: '980076175', +// address: 'Lönsstraße 9, 6020 Innsbruck', +// latitude: 47.262765, +// longitude: 11.419851, +// }, {distance: 1000}) +// client.reachableFrom({ +// type: 'location', +// id: '980076175', +// address: 'Lönsstraße 9, 6020 Innsbruck', +// latitude: 47.262765, +// longitude: 11.419851, +// }, { +// maxDuration: 30, +// }) + +.then((data) => { + console.log(require('util').inspect(data, {depth: null, colors: true})) +}) +.catch(console.error) diff --git a/p/ivb/index.js b/p/ivb/index.js new file mode 100644 index 00000000..e13387b0 --- /dev/null +++ b/p/ivb/index.js @@ -0,0 +1,104 @@ +'use strict' + +const {readFileSync} = require('fs') +const {join} = require('path') +const {Agent} = require('https') +const baseProfile = require('./base.json') + +const products = [{ + id: 'train-and-s-bahn', + mode: 'train', + bitmasks: [1, 2], + name: 'Bahn & S-Bahn', + short: 'Bahn & S-Bahn', + default: true, +}, { + id: 'u-bahn', + mode: 'train', + bitmasks: [4], + name: 'U-Bahn', + short: 'U-Bahn', + default: true, +}, { + id: 'tram', + mode: 'train', + bitmasks: [16], + name: 'Straßenbahn', + short: 'Straßenbahn', + default: true, +}, { + id: 'city-bus', + mode: 'bus', + bitmasks: [128], + name: 'Stadtbus', + short: 'Stadtbus', + default: true, +}, { + id: 'regional-bus', + mode: 'bus', + bitmasks: [64], + name: 'Regionalbus', + short: 'Regionalbus', + default: true, +}, { + id: 'long-distance-bus', + mode: 'bus', + bitmasks: [32], + name: 'Fernbus', + short: 'Fernbus', + default: true, +}, { + id: 'other-bus', + mode: 'bus', + bitmasks: [2048], + name: 'sonstige Busse', + short: 'sonstige Busse', + default: true, +}, { + id: 'aerial-lift', + mode: 'gondola', + bitmasks: [256], + name: 'Seil-/Zahnradbahn', + short: 'Seil-/Zahnradbahn', + default: true, +}, { + id: 'ferry', + mode: 'watercraft', + bitmasks: [512], + name: 'Schiff', + short: 'Schiff', + default: true, +}, { + id: 'on-call', + mode: 'taxi', + bitmasks: [1024], + name: 'Anrufsammeltaxi', + short: 'AST', + default: true, +}] + +// `fahrplan.ivb.at:443` doesn't provide the necessary CA certificate chain for +// Node.js to trust the certificate, so we manually add it. +// todo: fix this properly, e.g. by letting them know +const ca = readFileSync(join(__dirname, 'digicert-tls-rsa-sha256-2020-ca1.crt.pem')) +const agent = new Agent({ca}) +const transformReq = (ctx, req) => ({...req, agent}) + +const ivbProfile = { + ...baseProfile, + ver: '1.32', + transformReq, + + locale: 'at-DE', + timezone: 'Europe/Vienna', + + products, + + departuresGetPasslist: false, + departuresStbFltrEquiv: false, + refreshJourneyUseOutReconL: true, + trip: true, + reachableFrom: true, +} + +module.exports = ivbProfile diff --git a/p/ivb/readme.md b/p/ivb/readme.md new file mode 100644 index 00000000..313c6c85 --- /dev/null +++ b/p/ivb/readme.md @@ -0,0 +1,15 @@ +# IVB profile for `hafas-client` + +[*Innsbrucker Verkehrsbetriebe (IVB)*](https://de.wikipedia.org/wiki/Innsbrucker_Verkehrsbetriebe_und_Stubaitalbahn) is the local transport provider of [Innsbruck](https://en.wikipedia.org/wiki/Innsbruck). This profile adds *IVB* support to `hafas-client`. + +## Usage + +```js +const createClient = require('hafas-client') +const ivbProfile = require('hafas-client/p/ivb') + +// create a client with IVB profile +const client = createClient(ivbProfile, 'my-awesome-program') +``` + +Check out the [code examples](example.js). diff --git a/p/readme.md b/p/readme.md index cbf78af4..554ef1ea 100644 --- a/p/readme.md +++ b/p/readme.md @@ -38,6 +38,7 @@ HAFAS endpoint | wrapper library | docs | example code | profile name [Verkehrsgemeinschaft Osnabrück (VOS)](https://de.wikipedia.org/wiki/Verkehrsgemeinschaft_Osnabrück) | - | [docs](vos/readme.md) | [example](vos/example.js) | [`vos`](vos) [Aachener Verkehrsverbund (AVV)](https://de.wikipedia.org/wiki/Verkehrsgemeinschaft_Osnabrück) | - | [docs](avv/readme.md) | [example](avv/example.js) | [`avv`](avv) [Rejseplanen in Denmark](http://www.rejseplanen.dk) | - | [docs](rejseplanen/readme.md) | [example](rejseplanen/example.js) | [`rejseplanen`](rejseplanen) +[Innsbrucker Verkehrsbetriebe (IVB)](https://de.wikipedia.org/wiki/Innsbrucker_Verkehrsbetriebe_und_Stubaitalbahn) | - | [docs](ivb/readme.md) | [example](ivb/example.js) | [`ivb`](ivb) [Salzburg public transport (SVV)](https://de.wikipedia.org/wiki/Salzburger_Verkehrsverbund) | - | [docs](svv/readme.md) | [example](svv/example.js) | [`svv`](svv) [Verkehrsverbund Tirol (VVT)](https://de.wikipedia.org/wiki/Verkehrsverbund_Tirol) | - | [docs](vvt/readme.md) | [example](vvt/example.js) | [`vvt`](vvt) [*Kärntner Linien/Verkehrsverbund Kärnten (VKG/VVK)*](https://de.wikipedia.org/wiki/Verkehrsverbund_Kärnten) | - | [docs](vkg/readme.md) | [example](vkg/example.js) | [`vkg`](vkg) diff --git a/test/e2e/fixtures/adff894e23072236951ca9a5c20507d0 b/test/e2e/fixtures/adff894e23072236951ca9a5c20507d0 new file mode 100644 index 00000000..3e0d7c44 --- /dev/null +++ b/test/e2e/fixtures/adff894e23072236951ca9a5c20507d0 @@ -0,0 +1 @@ +{"ver":"1.32","lang":"deu","id":"9amsegmak2q4p28g","err":"OK","cInfo":{"code":"OK","url":"","msg":""},"graph":{"id":"standard","index":0},"subGraph":{"id":"global","index":0},"view":{"id":"standard","index":0,"type":"WGS84"},"svcResL":[{"meth":"LocMatch","err":"OK","res":{"common":{"remL":[{"type":"W","code":"WW","txtN":"WEBVIEW","url":"https://routenplaner.verkehrsauskunft.at/bin/query.exe/dn?tpl=webview_poi&performLocating=128&look_station=960145724&look_nv=get_infotext|yes|get_attributes|yes&look_stationpool=130"}],"txtInstL":[{"id":"street","type":"NONE","mode":"ADD"},{"id":"city","type":"NONE","mode":"ADD"}],"icoL":[{"res":"prod_bus","txtS":"R","fg":{"r":255,"g":255,"b":255},"bg":{"r":0,"g":121,"b":58},"zIdx":1000},{"res":"ADR"},{"res":"PCAT_E_TANKEN","zIdx":900}]},"match":{"field":"S","state":"L","locL":[{"lid":"A=1@O=Innsbruck Griesauweg@X=11439124@Y=47267511@U=81@L=476162400@B=1@p=1628121247@","type":"S","name":"Innsbruck Griesauweg","nameFormatted":{"text":"Innsbruck Griesauweg"},"icoX":0,"extId":"476162400","state":"F","crd":{"x":11439124,"y":47267511,"floor":0},"meta":true,"pCls":128,"wt":188,"isMainMast":true,"gidL":["at:47:61624"]},{"lid":"A=2@O=Griesauweg, 6020 Innsbruck@X=11437560@Y=47264401@U=103@b=980042853@B=1@p=1626331592@","type":"A","name":"Griesauweg, 6020 Innsbruck","nameFormatted":{"text":"Griesauweg, 6020 Innsbruck","textInstructionIntervalL":[{"startIndex":0,"endIndex":10,"textInstructionX":0},{"startIndex":10,"endIndex":26,"textInstructionX":1}]},"icoX":1,"state":"F","crd":{"x":11437560,"y":47264401}},{"lid":"A=4@O=SMATRICS GmbH und Co KG Griesauweg 28, 6020 Innsbruck@X=11438890@Y=47266963@U=130@L=960145724@B=1@p=1628123037@","type":"P","name":"SMATRICS GmbH und Co KG Griesauweg 28, 6020 Innsbruck","nameFormatted":{"text":"SMATRICS GmbH und Co KG Griesauweg 28, 6020 Innsbruck","textInstructionIntervalL":[{"startIndex":37,"endIndex":53,"textInstructionX":1}]},"icoX":2,"extId":"960145724","state":"F","crd":{"x":11438890,"y":47266963,"floor":0},"mcpData":{"type":"P","occupancy":"N","mcpid":"0","externalId":"SMATRICS GmbH und Co KG_ETF58257"},"msgL":[{"type":"REM","remX":0,"sty":"I","dspl":"U","tagL":["RES_LOC_WEB","RES_LOC_FLY_WEB"],"sort":684195840}]},{"lid":"A=2@O=Griessauweg, 3133 Traismauer@X=15728174@Y=48331070@U=103@b=980042941@B=1@p=1626331592@","type":"A","name":"Griessauweg, 3133 Traismauer","nameFormatted":{"text":"Griessauweg, 3133 Traismauer","textInstructionIntervalL":[{"startIndex":0,"endIndex":11,"textInstructionX":0},{"startIndex":11,"endIndex":28,"textInstructionX":1}]},"icoX":1,"state":"F","crd":{"x":15728174,"y":48331070}},{"lid":"A=2@O=Griesenauweg, 6370 Kitzbühel@X=12396844@Y=47451107@U=103@b=980042884@B=1@p=1626331592@","type":"A","name":"Griesenauweg, 6370 Kitzbühel","nameFormatted":{"text":"Griesenauweg, 6370 Kitzbühel","textInstructionIntervalL":[{"startIndex":0,"endIndex":12,"textInstructionX":0},{"startIndex":12,"endIndex":28,"textInstructionX":1}]},"icoX":1,"state":"F","crd":{"x":12396844,"y":47451107}}]}}}]} \ No newline at end of file diff --git a/test/e2e/fixtures/adff894e23072236951ca9a5c20507d0.headers b/test/e2e/fixtures/adff894e23072236951ca9a5c20507d0.headers new file mode 100644 index 00000000..89f658b6 --- /dev/null +++ b/test/e2e/fixtures/adff894e23072236951ca9a5c20507d0.headers @@ -0,0 +1,32 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 05 Aug 2021 18:10:05 GMT", + "server": "Apache", + "content-length": "1119", + "content-type": "application/json; charset=utf-8", + "connection": "close" + }, + "url": "https://fahrplan.ivb.at/bin/mgate.exe", + "time": 372, + "request": { + "method": "POST", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, br, deflate" + ], + "Accept": [ + "application/json" + ], + "user-agent": [ + "public-tra44fe4bad857bnsport/hafas-client:test" + ], + "Content-Length": [ + "263" + ] + } + } +} \ No newline at end of file diff --git a/test/e2e/ivb.js b/test/e2e/ivb.js new file mode 100644 index 00000000..bac80418 --- /dev/null +++ b/test/e2e/ivb.js @@ -0,0 +1,35 @@ +'use strict' + +const tap = require('tap') + +const {createWhen} = require('./lib/util') +const createClient = require('../..') +const ivbProfile = require('../../p/ivb') +const createValidate = require('./lib/validate-fptf-with') + +const when = createWhen(ivbProfile.timezone, ivbProfile.locale) +const cfg = { + when, + stationCoordsOptional: false, + products: ivbProfile.products, + maxLatitude: 47.9504, + maxLongitude: 17.0892, + minLatitude: 45.7206, + minLongitude: 7.8635, +} +const validate = createValidate(cfg) + +const client = createClient(ivbProfile, 'public-transport/hafas-client:test') + +const innsbruckGriesauweg = '476162400' + +tap.test('locations named "griesauweg"', async (t) => { + const locations = await client.locations('griesauweg') + + validate(t, locations, 'locations', 'locations') + t.ok(locations.some((l) => { + return l.station && l.station.id === innsbruckGriesauweg || l.id === innsbruckGriesauweg + }), 'Innsbruck Griesauweg not found') + + t.end() +}) diff --git a/tools/pull-profile-base-data.sh b/tools/pull-profile-base-data.sh index 8bbc09ca..26065706 100755 --- a/tools/pull-profile-base-data.sh +++ b/tools/pull-profile-base-data.sh @@ -60,6 +60,7 @@ node -p "$query" "$src/de/vmt-hafas-mgate.json" >../p/vmt/base.json node -p "$query" "$src/de/vos-hafas-mgate.json" >../p/vos/base.json node -p "$query" "$src/de/vrn-hafas-mgate.json" >../p/vrn/base.json node -p "$query" "$src/de/vsn-hafas-mgate.json" >../p/vsn/base.json +node -p "$query" "$src/at/ivb-hafas-mgate.json" >../p/ivb/base.json node -p "$query" "$src/at/vvt-hafas-mgate.json" >../p/vvt/base.json node -p "$query" "$src/at/vvv-hafas-mgate.json" >../p/vvv/base.json node -p "$query" "$src/ch/bls-hafas-mgate.json" >../p/bls/base.json