Compare commits

..

12 Commits

Author SHA1 Message Date
Bas Kloosterman 325d8ac7c2 Use different certificates for retrieval from different services 12 months ago
Bas Kloosterman c49da5c76e Remove extbin 12 months ago
Bas Kloosterman 76f8f4cb29 Remove logging 12 months ago
Bas Kloosterman 55b333bb98 dvza make external addr possible, rebase 12 months ago
Bas Kloosterman cf91da65d3 Remove js output 12 months ago
Bas Kloosterman d1b06bc3c6 Fix docker compose 12 months ago
Bas Kloosterman 3e237b8ef3 Update ignore files 12 months ago
Bas Kloosterman 1670759499 Rename certgen -> cryptoutil 12 months ago
Bas Kloosterman b90d8fe800 Update module name end dependencies, change case 12 months ago
Bas Kloosterman 32926ad3e7 Add different versions of ediviewer (amd64|arm64) 12 months ago
Bas Kloosterman 3461e04283 Make external grpc address configurable 12 months ago
Bas Kloosterman 674b3505ef Move patients 12 months ago
  1. 2
      dvzaservice/app/src/Connection.js
  2. 1
      dvzaservice/app/src/Registrations.js
  3. 11
      dvzaservice/main.go
  4. BIN
      extbin/ediviewer
  5. 1
      extbin/medeur.json
  6. 520
      extbin/template.html
  7. 1
      his/openapiclient.go
  8. 2
      his/srv.go
  9. 2
      whiteboxservice/app/src/Connection.js
  10. 1
      whiteboxservice/app/src/Registrations.js
  11. 14
      whiteboxservice/main.go
  12. 18
      whiteboxservice/openapisrv.go
  13. 32
      whiteboxservice/srv.go

@ -40,8 +40,6 @@ const Connection = () => {
useEffect(() => {
fetch(`/api/connections/${params.connId}/${params.serviceId}`).then(x => x.json()).then(x => setService(x) )
}, [])
console.log('connection', connection)
console.log('service', service)
return (
<div>
<h1 className="t-page-header">Verbinding</h1>

@ -7,7 +7,6 @@ const App = () => {
useEffect(() => {
fetch('/api/registrations').then(x => x.json()).then(x => setRegistrations(x) )
}, [])
console.log('registrations', registrations)
return (
<div>
<h1 className="t-page-header">Registratie verzoeken</h1>

@ -55,20 +55,9 @@ func loadCert() *tls.Certificate {
func loadKeyPair() credentials.TransportCredentials {
certificate := loadCert()
// data, err := ioutil.ReadFile("certs/ca.crt")
// if err != nil {
// panic("failed to load CA file: " + err.Error())
// }
// capool := x509.NewCertPool()
// if !capool.AppendCertsFromPEM(data) {
// panic("can't add ca cert")
// }
tlsConfig := &tls.Config{
ClientAuth: tls.RequestClientCert,
Certificates: []tls.Certificate{*certificate},
// ClientCAs: capool,
}
return credentials.NewTLS(tlsConfig)
}

Binary file not shown.

@ -1 +0,0 @@
{"format":[{"name":"UNB","description":"Interchange header"},{"name":"UNH","description":"Head of message"},{"name":"BGM","children":[{"name":"DTM","description":"Datum aangemaakt"},{"name":"RFF","description":"Referenties"},{"name":"FTX","description":"Bericht afhankelijke mededeling"}],"description":"Begin van het bericht"},{"name":"S01","children":[{"name":"NAD","description":"Naam en adres"},{"name":"ADR","description":"Adres"},{"name":"COM","description":"Telefoon- en fax-nummers"},{"name":"RFF"},{"name":"DTM"},{"name":"LAN"},{"name":"SPR","description":"Type medewerker"},{"name":"QUA","description":"Kwalificatie"},{"name":"FTX","description":"Vrije tekst"}],"description":"Medebehandelaar"},{"name":"S02","children":[{"name":"PNA","description":"Naam van de patient"},{"name":"ADR","description":"Adres-patient"},{"name":"COM","description":"Telefoon- en fax-nummers"},{"name":"RFF","description":"Referenties"},{"name":"DTM","description":"Tijdsindicatie"},{"name":"NAT"},{"name":"LAN"},{"name":"LOC"},{"name":"PDI","description":"Demografische gegevens"},{"name":"QUA","description":"Kwalificatie"},{"name":"STS"},{"name":"INS","description":"Verzekeringsgegevens"},{"name":"REL"},{"name":"FTX","description":"Vrije tekst"},{"name":"S03","children":[{"name":"DTM","description":"Tijdsindicatie"},{"name":"S04","children":[{"name":"CIN","description":"Diagnose signalering of risico-factor"},{"name":"PTY","description":"Prioriteit"},{"name":"RFF","description":"Referentie naar groep 1"},{"name":"FTX","description":"Vrije tekst"},{"name":"DTM","description":"Tijdsindicatie"}],"description":"Medisch kenmerk"},{"name":"S05","children":[{"name":"INV"},{"name":"DTM"}]}],"description":"Contact onafhankelijke medische gegevens"},{"name":"S06","children":[{"name":"DTM","description":"Datum/tijd van een contact"},{"name":"RFF","description":"Verantwoordelijke persoon"},{"name":"S07","children":[{"name":"FTX"},{"name":"PTY","description":"Prioriteit"},{"name":"RFF","description":"Probleem/episode"},{"name":"DTM","description":"Datum/tijd van een contact"}],"description":"Ongeclassificeerde journaalregel"},{"name":"S08","children":[{"name":"INV","description":"Meting identificatie"},{"name":"PTY","description":"Prioriteit"},{"name":"RFF","description":"Probleem/episode"},{"name":"RSL","description":"Resultaat meting"},{"name":"RND","description":"Normaalwaarden"},{"name":"FTX","description":"Resultaat"},{"name":"DTM","description":"Datum/tijd"}],"description":"Metingen"},{"name":"S09","children":[{"name":"CIN","description":"Diagnose"},{"name":"PTY","description":"Prioriteit"},{"name":"RFF","description":"Probleem/episode"},{"name":"FTX","description":"Diagnose in vrije tekst"},{"name":"DTM","description":"Datum/tijd"}],"description":"Diagnoses"},{"name":"S10","children":[{"name":"SPR","description":"Specialisme"},{"name":"PTY","description":"Prioriteit"},{"name":"RFF","description":"Probleem/episode"},{"name":"PRC","description":"Soort verwijzing"},{"name":"FTX","description":"Beschrijving"},{"name":"DTM","description":"Datum/tijd"}],"description":"Verwijzingen of terugverwijzingen"},{"name":"S11","children":[{"name":"CLI","description":"Type therapie"},{"name":"PTY","description":"Prioriteit"},{"name":"RFF","description":"Probleem/episode"},{"name":"FTX","description":"Vrije tekst"},{"name":"QTY","description":"Hoeveelheid"},{"name":"DNL","children":[{"name":"DSG","description":"Dose administration"},{"name":"FTX","description":"Vrije tekst"}],"description":"Dosering Nederlandse stijl"},{"name":"SPC","children":[{"name":"QTY","description":"Hoeveelheid"}],"description":"Afzonderlijke stoffen van recept"},{"name":"CIN","description":"Indicatie"},{"name":"SPR","description":"Specialisme voorschrijver"},{"name":"DTM","description":"Datum/tijd"}],"description":"Therapie"}],"description":"Journaalregel"}],"description":"Pati\u00ebnt"},{"name":"UNT","description":"Einde van het bericht"},{"name":"UNZ","description":"Einde uitwisseling"}]}

@ -1,520 +0,0 @@
<!DOCTYPE html><html><head>
<meta charset="utf-8">
<title>{{.Patient.Name}} — MEDEUR</title>
<style>
body { margin: 1em auto; font-size: 12pt; font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; }
@media screen and (max-width: 700px) {
body { width: 700px; }
}
@media screen and (min-width: 1200px) {
body { width: 1200px; }
}
* { margin: 0; padding: 0; box-sizing: border-box; }
h3 { margin-bottom: 8px; }
ul { list-style-type: none; }
li + li { margin-top: 10px; }
td { vertical-align: top; }
.seg { margin-top: 8px; padding: 8px 10px; border: 0 solid #e7e7e7; border-width: 0 1px 1px 1px; }
.seg-hdr { margin-top: 8px; border-top-width: 1px; background: #F8F8F8; }
.seg-hdr-white { margin-top: 8px; background: #FFFFFF; border-color: transparent; }
a { color: royalblue }
table.patient th { text-align: left; padding-right: 1em }
table.SOEPkind { margin: -6px 0 }
table.SOEPkind tr { height: 1em }
table.SOEPkind th { text-align: left; width: 32px; height: 1em; font-weight: normal }
table.results th { text-align: left }
.error { position: fixed; top: 10px; margin-left: 32px; border: 2px solid #000000; background-color: #FF2222; }
.row + .row { margin-top: 4px; }
.table { font-size: 100%; width: 100%; border-spacing: 0; border-collapse: collapse; }
.table tr { font-size: 100% }
.table td { font-size: 100% }
.table th { font-size: 100%; text-align: left; }
.table tbody td { font-size: 100%; text-align: left; padding: 2px 8px 2px 0; }
.table thead th { font-size: 100%; padding: 0 0 2px 0; }
.table tr.highlight { background: #E3E9E3 }
.column-attn { width: 1em; }
.column-code { width: 4em; }
.column-date { width: 6.5em; }
.column-small-name { width: 10em; }
.column-medium-name { width: 14em; }
.column-large-name { width: 28em; }
.column-name { width: 20em; }
.column-instr{ width: 15em; }
.column-quantity { width: 12em; }
.no-margin { margin-bottom: 0px; }
.seg-date { float: left; width: 6.5em; }
.seg-content-offset { margin-left: 6.5em }
.column-result-id { width: 16em }
.column-result-name { width: 10em }
h3.fold-toggle { margin-bottom: 8px }
h4.fold-toggle { margin-bottom: 0; margin-top: 4px }
h3.fold-toggle.fold-toggle-hidden { margin-bottom: 0 }
h4.fold-toggle.fold-toggle-hidden { margin-bottom: 4px }
.fold-toggle .fold-marker:before,
h3.fold-toggle:before,
h4.fold-toggle:before { content: "▾ " }
.fold-toggle.fold-toggle-hidden .fold-marker:before,
h3.fold-toggle.fold-toggle-hidden:before,
h4.fold-toggle.fold-toggle-hidden:before { content: "▸ " }
.fold-toggle { cursor: pointer; }
.fold-hidden {display: none}
.hidden
{
display: none !important
}
textarea
{
border: 1px solid #333;
padding: .5em;
font-size: 100%
}
input[type=submit]
{
font-size: 90%;
padding: .25em
}
button
{
font-size: 75%;
padding: .25em
}
</style></head>
<body>
<div class="container">
{{define "person-row"}}
<tr id="person-{{.Anchor}}">
<td class="column-small-name">{{if .Name}}{{.Name}}{{else}}<em>Geen naam</em>{{end}}</td>
<td class="column-small-name">{{.Function}}</td>
<td class="column-medium-name">{{.Address}}</td>
<td class="column-small-name">{{if .AGB}}AGB: {{.AGB}}{{end}}</td>
</tr>{{end}}
{{define "medi-group-epi"}}
{{$root := .}}
<table class="table">
<thead>
<tr>
<th class="column-date">Datum</th>
{{if HasEndDates .Episodes }}
<th class="column-date">Einddatum</th>
{{end}}
<th class="column-code">Type</th>
<th class="column-date">ICPC</th>
<th class="column-name">Beschrijving</th>
{{if eq .Extra.verbose_icpc_description "true"}}
<th class="column-desc">Beschrijving arts</th>
{{else}}
{{end}}
<th class="column-desc"></th>
</tr>
</thead>
<tbody>
{{range .Episodes}}
<tr {{if .Anchor}} id="medigroup-{{.Anchor}}"{{end}}>
<td>{{.Date}}</td>
{{if HasEndDates $.Episodes }}
<td style="{{if EndDateInPast .EndDate}}color: red;{{end}}">{{.EndDate}}</td>
{{end}}
<td>{{.Type}}</td>
<td>{{.ICPC}}</td>
{{if eq $root.Extra.verbose_icpc_description "true"}}
<td>{{.Title}}</td>
<td>{{.Description}}</td>
{{else}}
{{if eq .Description ""}}
<td colspan="2">{{.Title}}</td>
{{else}}
<td colspan="2">{{.Description}}</td>
{{end}}
{{end}}
</tr>
{{end}}
</tbody>
</table>
{{end}}
{{define "medi-group-ica"}}
{{$root := .}}
<table class="table">
<thead>
<tr>
<th class="column-date">Datum</th>
<th class="column-code">Type</th>
<th class="column-date">ICPC</th>
<th class="column-name" colspan="2">Beschrijving</th>
{{if eq $root.Extra.verbose_icpc_description "true"}}
<th class="column-desc"></th>
{{else}}
{{end}}
</tr>
</thead>
<tbody>
{{range .Indicators}}
<tr{{if .Anchor}} id="medigroup-{{.Anchor}}"{{end}}>
<td>{{.Date}}</td>
<td>{{.Type}}</td>
<td>{{.ICPC}}</td>
<td>{{.Title}}</td>
{{if eq $root.Extra.verbose_icpc_description "true"}}
<td>{{.Description}}</td>
{{else}}
<td></td>
{{end}}
</tr>{{end}}
</tbody>
</table>
{{end}}
<div class="seg seg-hdr" data-his="{{.HIS}}">
<h3>Huisarts</h3>
<table class="table">
{{template "person-row" .GP}}
{{if .Pharmacy.Anchor}}{{template "person-row" .Pharmacy}}{{end}}
</table>
{{if .Practitioners}}
<h4 data-fold-toggle="practicioners" data-fold-hide="1">Medebehandelaren</h4>
<div data-fold="practicioners">
<table class="table">{{range .Practitioners}}
{{template "person-row" .}}{{end}}
</table>
</div>
{{end}}
</div>
<div class="seg seg-hdr">
<h3>Patiënt</h3>
<table class="patient">
<tr>
<th>Naam:
<td>{{.Patient.Name}}
{{if .Patient.BSN}}
<tr>
<th>BSN:
<td>{{.Patient.BSN}}
{{end}}
<tr>
<th>Geboortedatum:
<td>{{.Patient.Birthdate}}
<tr>
<th>Adres:
<td>{{.Patient.Address}}
<tr>
<th>Geslacht:
<td>{{.Patient.Gender}}
{{range .Patient.OtherFields}}
<tr>
<th>{{.Key}}:
<td{{if eq .Key "Toegepast filter"}} title="Een filter is een (standaard) filter dat door een huisarts over alle of een deel van de patiëntendossiers wordt toegepast. De minimale professionele samenvatting (PS) bevat een samenvatting van alleen zeer recente informatie uit het huisartsdossier, met alleen actuele / chronische medicatie. Dit is minder informatie dan de standaard NHG PS, die journaalregels tot 4 maanden terug, of de laatste 5 consultverslagen kan bevatten. Houd er svp rekening mee dat geen enkel type PS alle, of gegarandeerd volledige of correcte informatie bevat."{{end}}>{{.Value}}
{{end}}
</table>
</div>
{{if .Memo}}
<div class="seg seg-hdr">
<h3>Memo</h3>
{{.Memo}}
</div>
{{end}}
{{if .Episodes}}
<div class="seg seg-hdr">
<h3>Episodelijst</h3>
{{template "medi-group-epi" .}}
</div>
{{end}}
{{if .Indicators}}
<div class="seg seg-hdr">
<h3>Contra-indicaties, interacties en allergie&#235;n</h3>
{{template "medi-group-ica" .}}
</div>
{{end}}
{{if .Medication}}
<div class="seg seg-hdr">
<h3 data-fold-toggle="med-table">Medicatieoverzicht</h3>
<table data-fold="med-table" class="table">
<thead>
<tr>
<th class="column-large-name">Recept</th>
<th class="column-instr">Gebruiksvoorschrift</th>
<th class="column-quantity">Hoeveelheid</th>
<th class="column-date">Ingang</th>
<th class="column-date">Vervalt</th>
</tr>
</thead>
<tbody>
{{range $index, $med := .Medication}}
{{if gt (len $med.Fold) 1}}
<tr data-fold-toggle="medfold-{{$index}}" data-fold-hide="1">
<td>{{$med.Recipe}}</td>
<td>{{$med.Instructions}}</td>
<td>{{ YieldDosage $med }}</td>
<td>{{$med.StartDate}}</td>
<td>{{$med.EndDate}}</td>
</tr>
{{range $fold := $med.Fold}}
<tr data-fold="medfold-{{$index}}">
<td></td>
<td>{{ if ne $med.Instructions $fold.Instructions}}{{$fold.Instructions}}{{else}}{{end}}</td>
<td>{{ YieldDosage $fold }}</td>
<td>{{$fold.StartDate}}</td>
<td>{{$fold.EndDate}}</td>
</tr>
{{end}}
{{else}}
<tr>
<td>{{$med.Recipe}}</td>
<td>{{$med.Instructions}}</td>
<td>{{ YieldDosage $med }}</td>
<td>{{$med.StartDate}}</td>
<td>{{$med.EndDate}}</td>
</tr>
{{end}}
{{end }}
</tbody>
</table>
</div>
{{end}}
{{if .Journal}}
<div class="seg seg-hdr-white">
<h3>Journaal</h3>
</div>
{{range .Journal}}
<div class="seg seg-hdr">
<div class="seg-date">{{.Date}}</div>
<div class="seg-content-offset" title="{{.AuthorName}}{{if .Kind}} ({{.Kind}}){{end}}">
{{if .Results}}
<div class="row">
<table class="results">
<thead>
<tr>
<th class="column-result-id">Identificatie</th>
<th class="column-result-name">Resultaat</th>
<th class="column-result-desc">Beschrijving</th>
</tr>
</thead>
<tbody>
{{range .Results}}
<tr {{if .Episode}}data-episode="{{.Episode}}"{{end}}><td>{{.Kind}}</td>
<td>{{.Result}}</td>
<td>{{if eq .Identification "Buiten normaalwaarde"}}<strong>{{.Identification}}</strong>{{else}}{{.Identification}}{{end}}
{{if and .Identification .Description}}<br>{{end}}
{{.Description}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{end}}
{{range .Lines}}
<div class="row"{{if .Episode}} data-episode="{{.Episode}}"{{end}}>
<table class="SOEPkind">
<tr>
{{if .SOEP}}
<th style="padding-top: 10px; vertical-align: top;">{{.SOEP}}:
<td style="padding-top: 10px; vertical-align: top;">{{ConvertLinebreaks .Text}}
{{end}}
{{if .Kind}}
<th style="padding-top: 10px; vertical-align: top;">{{.Kind}}{{if .Text}}:{{end}}
<td style="padding-top: 10px; vertical-align: top;">{{ConvertLinebreaks .Text}}
{{end}}
</tr>
</table>
</div>
{{end}}
</div>
</div>
{{end}}
{{end}}
{{if .Extra.csrf_token }}
<div class="seg seg-hdr-white">
<br>
<h3 id="feedback-header"><button onClick="feedbackHeaderClicked()">Notitie schrijven</button></h3>
<form id="feedback-form" class="hidden" method="POST" onSubmit="sendFeedback(); return false"> <!-- TODO: contruct proper URL in golang -->
<input type="hidden" name="csrf_token" value="{{.Extra.csrf_token}}" id="csrf">
<p><br><textarea id="feedback-textarea" rows="7" cols="50"></textarea>
<p><br><input type="submit" value="Opsturen">
</form>
</div>
{{end}}
</div>
<script>
(function() {
var folds = document.querySelectorAll('[data-fold-toggle]');
for (var i = 0; i < folds.length; i++) {
(function(btn) {
var t = btn.getAttribute('data-fold-toggle');
var fds = document.querySelectorAll('[data-fold="' + t + '"]');
btn.classList.add('fold-toggle');
var hidden = false;
var sync = function() {
if (hidden) {
btn.classList.add('fold-toggle-hidden');
} else {
btn.classList.remove('fold-toggle-hidden');
}
for (var j = 0; j < fds.length; j++) {
var e = fds[j].classList;
if (hidden) {
e.add('fold-hidden');
} else {
e.remove('fold-hidden');
}
}
setTimeout(send_height_to_parent, 0);
};
if (btn.getAttribute('data-fold-hide') == '1') {
hidden = true;
}
btn.addEventListener('click', function() {
hidden = !hidden;
sync();
});
sync();
})(folds[i]);
}
})();
function feedbackHeaderClicked()
{
toggle('feedback-form')
var textarea = document.getElementById('feedback-textarea')
textarea.focus()
}
function toggle(id)
{
var elem = document.getElementById(id)
if (elem)
{
var className = elem.getAttribute('class')
if (className == 'hidden')
{
elem.setAttribute('class', '')
}
else
{
elem.setAttribute('class', 'hidden')
}
}
}
function getXMLHttpRequest()
{
if (window.XMLHttpRequest)
{
return new XMLHttpRequest()
}
else if (window.ActiveXObject)
{
return new ActiveXObject('Microsoft.XMLHTTP')
}
}
function sendFeedback()
{
var URL = document.location.href.replace('preview', '') + 'pushback'
var textarea = document.getElementById('feedback-textarea')
var message = textarea.value
var csrf_element = document.getElementById('csrf')
var csrf= csrf_element.value
var xmlhttp = getXMLHttpRequest()
xmlhttp.onreadystatechange = function() { sendFeedbackHandler(xmlhttp) }
params = '';
params += 'csrf_token=' + encodeURIComponent(csrf) + '&'
params += 'message=' + encodeURIComponent(message)
xmlhttp.open('POST', URL, true)
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xmlhttp.setRequestHeader('Content-length', params.length)
xmlhttp.setRequestHeader('Connection', 'close')
xmlhttp.send(params)
}
function sendFeedbackHandler(xmlhttp)
{
if (xmlhttp.readyState != 4) { return }
if (xmlhttp.status == 200)
{
try
{
var response = JSON.parse(xmlhttp.responseText)
if (response.success) {
alert('Feedback is succesvol verstuurd.')
toggle('feedback-form')
} else {
alert('Er is iets fout gegaan: ' + response.error)
}
}
catch (e)
{
alert('Fout bij versturen feedback.')
}
}
else
{
alert('Fout bij versturen feedback.')
}
}
function send_height_to_parent() {
var body = document.body,
html = document.documentElement;
var height = Math.max( body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight );
var msg = {
"height": height,
};
parent.postMessage(msg, "*");
}
send_height_to_parent();
</script></body></html>

@ -40,7 +40,6 @@ func getUnauthenticatedClient(addr string) (okapi.OkAPIClient, error) {
return nil, err
}
// defer serviceProvider.Close()
return okapi.NewOkAPIClient(conn), nil
}

@ -61,7 +61,6 @@ func loadKeyPair() credentials.TransportCredentials {
tlsConfig := &tls.Config{
ClientAuth: tls.RequestClientCert,
Certificates: []tls.Certificate{*certificate},
// ClientCAs: capool,
}
return credentials.NewTLS(tlsConfig)
}
@ -265,6 +264,7 @@ func (srv *HISServer) Authenticate(c *gin.Context) {
raw := ""
method := ""
if len(c.Request.TLS.PeerCertificates) > 0 {
jwk, err := cryptoutil.PublicKeyToJWK(c.Request.TLS.PeerCertificates[0].PublicKey)

@ -40,8 +40,6 @@ const Connection = () => {
useEffect(() => {
fetch(`/api/connections/${params.connId}/${params.serviceId}`).then(x => x.json()).then(x => setService(x) )
}, [])
console.log('connection', connection)
console.log('service', service)
return (
<div>
<h1 className="t-page-header">Patiënten</h1>

@ -7,7 +7,6 @@ const App = () => {
useEffect(() => {
fetch('/api/registrations').then(x => x.json()).then(x => setRegistrations(x) )
}, [])
console.log('registrations', registrations)
return (
<div>
<h1 className="t-page-header">Registratie verzoeken</h1>

@ -3,6 +3,7 @@ package main
import (
"context"
"crypto/tls"
"fmt"
"io/ioutil"
"log"
"net"
@ -23,8 +24,8 @@ var patientIf = "0.0.0.0:8085"
var binFolder = "./bin/arm64"
func loadCert() *tls.Certificate {
_, err := os.Stat("certs/client.crt")
func loadCert(name string) *tls.Certificate {
_, err := os.Stat(fmt.Sprintf("certs/%s.crt", name))
if err != nil {
_, _, certPem, keyPem, err := cryptoutil.GenCert("whitebox", "whitebox")
@ -37,15 +38,15 @@ func loadCert() *tls.Certificate {
panic(err)
}
if err := ioutil.WriteFile("certs/client.crt", []byte(certPem), 0600); err != nil {
if err := ioutil.WriteFile(fmt.Sprintf("certs/%s.crt", name), []byte(certPem), 0600); err != nil {
panic(err)
}
if err := ioutil.WriteFile("certs/client.key", []byte(keyPem), 0600); err != nil {
if err := ioutil.WriteFile(fmt.Sprintf("certs/%s.key", name), []byte(keyPem), 0600); err != nil {
panic(err)
}
}
certificate, err := tls.LoadX509KeyPair("certs/client.crt", "certs/client.key")
certificate, err := tls.LoadX509KeyPair(fmt.Sprintf("certs/%s.crt", name), fmt.Sprintf("certs/%s.key", name))
if err != nil {
panic("Load client certification failed: " + err.Error())
@ -55,12 +56,11 @@ func loadCert() *tls.Certificate {
}
func loadKeyPair() credentials.TransportCredentials {
certificate := loadCert()
certificate := loadCert("client")
tlsConfig := &tls.Config{
ClientAuth: tls.RequestClientCert,
Certificates: []tls.Certificate{*certificate},
// ClientCAs: capool,
}
return credentials.NewTLS(tlsConfig)
}

@ -45,6 +45,8 @@ type OkAPIServer struct {
okapi.UnimplementedOkAPIServer
data *gorm.DB
clientCert tls.Certificate
visiteCert tls.Certificate
wnhCert tls.Certificate
}
func (srv *OkAPIServer) LoadData(location string) error {
@ -307,7 +309,15 @@ func (srv *OkAPIServer) EnableService(
AuthConfig: sharedmodel.NewAuthConfig(in.Fetch.Auth),
}
publicKey, err := cryptoutil.PublicKeyToJWKJson(cryptoutil.ExtractPublicKey(srv.clientCert.PrivateKey))
var cert tls.Certificate
if in.ServiceId == "wbx:visitelijst" {
cert = srv.visiteCert
} else if in.ServiceId == "wbx:waarneming" {
cert = srv.wnhCert
}
publicKey, err := cryptoutil.PublicKeyToJWKJson(cryptoutil.ExtractPublicKey(cert.PrivateKey))
if err != nil {
return nil, fmt.Errorf("Error retrieving pub key: %v", err)
@ -621,9 +631,13 @@ func (srv *OkAPIServer) ListPatientRegistrations(
}
func NewServer() *OkAPIServer {
cert := loadCert()
cert := loadCert("client")
visiteCert := loadCert("visite")
wnhCert := loadCert("wnh")
return &OkAPIServer{
clientCert: *cert,
visiteCert: *visiteCert,
wnhCert: *wnhCert,
}
}

@ -21,6 +21,8 @@ type UIService struct {
srv *http.Server
inited bool
clientCert tls.Certificate
visiteCert tls.Certificate
wnhCert tls.Certificate
data *gorm.DB
}
@ -117,14 +119,21 @@ func (srv *UIService) GetPatient(c *gin.Context) {
}
url := fmt.Sprintf("%v/%v/%v", protoconfig["url"], "patients", protometa["patientID"])
req, _ := http.NewRequest("GET", url, nil)
var cert tls.Certificate
if serviceConfig.Service.ServiceID == "wbx:visitelijst" {
cert = srv.visiteCert
} else if serviceConfig.Service.ServiceID == "wbx:waarneming" {
cert = srv.wnhCert
}
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
Certificates: []tls.Certificate{srv.clientCert},
Certificates: []tls.Certificate{cert},
},
},
}
@ -224,12 +233,19 @@ func (srv *UIService) GetRegistrations(c *gin.Context) {
}
func NewUIServer(addr string) *UIService {
cert := loadCert()
srv := &UIService{srv: &http.Server{
Addr: addr,
Handler: gin.Default(),
}, clientCert: *cert}
cert := loadCert("client")
visiteCert := loadCert("visite")
wnhCert := loadCert("wnh")
srv := &UIService{
srv: &http.Server{
Addr: addr,
Handler: gin.Default(),
},
clientCert: *cert,
visiteCert: *visiteCert,
wnhCert: *wnhCert,
}
return srv
}

Loading…
Cancel
Save