Merge pull request #420 from dannyrb/docs/orthanc-proxy
Docs/orthanc proxy
@ -1,10 +1,16 @@
|
|||||||
|
# Output
|
||||||
dist/
|
dist/
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
node_modules/
|
node_modules/
|
||||||
.git
|
|
||||||
|
# Root
|
||||||
|
README.md
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
|
||||||
|
# Misc. Config
|
||||||
|
.git
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.gitignore
|
.gitignore
|
||||||
README.md
|
|
||||||
.vscode
|
.vscode
|
||||||
.circleci
|
.circleci
|
||||||
example/
|
|
||||||
|
|||||||
48
docker/Nginx-Orthanc/config/nginx.conf
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
worker_processes 1;
|
||||||
|
|
||||||
|
events { worker_connections 1024; }
|
||||||
|
|
||||||
|
http {
|
||||||
|
|
||||||
|
upstream orthanc-server {
|
||||||
|
server orthanc:8042;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
# CORS Magic
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
add_header 'Access-Control-Allow_Credentials' 'true';
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
|
||||||
|
|
||||||
|
location / {
|
||||||
|
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
add_header 'Access-Control-Allow_Credentials' 'true';
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
|
||||||
|
add_header 'Access-Control-Max-Age' 1728000;
|
||||||
|
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||||
|
add_header 'Content-Length' 0;
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_pass http://orthanc:8042;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Host $server_name;
|
||||||
|
|
||||||
|
# CORS Magic
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
add_header 'Access-Control-Allow_Credentials' 'true';
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
89
docker/Nginx-Orthanc/config/orthanc.json
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"Name": "Orthanc inside Docker",
|
||||||
|
"StorageDirectory": "/var/lib/orthanc/db",
|
||||||
|
"IndexDirectory": "/var/lib/orthanc/db",
|
||||||
|
"StorageCompression": false,
|
||||||
|
"MaximumStorageSize": 0,
|
||||||
|
"MaximumPatientCount": 0,
|
||||||
|
"LuaScripts": [],
|
||||||
|
"Plugins": ["/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"],
|
||||||
|
"ConcurrentJobs": 2,
|
||||||
|
"HttpServerEnabled": true,
|
||||||
|
"HttpPort": 8042,
|
||||||
|
"HttpDescribeErrors": true,
|
||||||
|
"HttpCompressionEnabled": true,
|
||||||
|
"DicomServerEnabled": true,
|
||||||
|
"DicomAet": "ORTHANC",
|
||||||
|
"DicomCheckCalledAet": false,
|
||||||
|
"DicomPort": 4242,
|
||||||
|
"DefaultEncoding": "Latin1",
|
||||||
|
"DeflatedTransferSyntaxAccepted": true,
|
||||||
|
"JpegTransferSyntaxAccepted": true,
|
||||||
|
"Jpeg2000TransferSyntaxAccepted": true,
|
||||||
|
"JpegLosslessTransferSyntaxAccepted": true,
|
||||||
|
"JpipTransferSyntaxAccepted": true,
|
||||||
|
"Mpeg2TransferSyntaxAccepted": true,
|
||||||
|
"RleTransferSyntaxAccepted": true,
|
||||||
|
"UnknownSopClassAccepted": false,
|
||||||
|
"DicomScpTimeout": 30,
|
||||||
|
|
||||||
|
"RemoteAccessAllowed": true,
|
||||||
|
"SslEnabled": false,
|
||||||
|
"SslCertificate": "certificate.pem",
|
||||||
|
"AuthenticationEnabled": false,
|
||||||
|
"RegisteredUsers": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"DicomModalities": {},
|
||||||
|
"DicomModalitiesInDatabase": false,
|
||||||
|
"DicomAlwaysAllowEcho": true,
|
||||||
|
"DicomAlwaysAllowStore": true,
|
||||||
|
"DicomCheckModalityHost": false,
|
||||||
|
"DicomScuTimeout": 10,
|
||||||
|
"OrthancPeers": {},
|
||||||
|
"OrthancPeersInDatabase": false,
|
||||||
|
"HttpProxy": "",
|
||||||
|
|
||||||
|
"HttpVerbose": true,
|
||||||
|
|
||||||
|
"HttpTimeout": 10,
|
||||||
|
"HttpsVerifyPeers": true,
|
||||||
|
"HttpsCACertificates": "",
|
||||||
|
"UserMetadata": {},
|
||||||
|
"UserContentType": {},
|
||||||
|
"StableAge": 60,
|
||||||
|
"StrictAetComparison": false,
|
||||||
|
"StoreMD5ForAttachments": true,
|
||||||
|
"LimitFindResults": 0,
|
||||||
|
"LimitFindInstances": 0,
|
||||||
|
"LimitJobs": 10,
|
||||||
|
"LogExportedResources": false,
|
||||||
|
"KeepAlive": true,
|
||||||
|
"TcpNoDelay": true,
|
||||||
|
"HttpThreadsCount": 50,
|
||||||
|
"StoreDicom": true,
|
||||||
|
"DicomAssociationCloseDelay": 5,
|
||||||
|
"QueryRetrieveSize": 10,
|
||||||
|
"CaseSensitivePN": false,
|
||||||
|
"LoadPrivateDictionary": true,
|
||||||
|
"Dictionary": {},
|
||||||
|
"SynchronousCMove": true,
|
||||||
|
"JobsHistorySize": 10,
|
||||||
|
"SaveJobs": true,
|
||||||
|
"OverwriteInstances": false,
|
||||||
|
"MediaArchiveSize": 1,
|
||||||
|
"StorageAccessOnFind": "Always",
|
||||||
|
"MetricsEnabled": true,
|
||||||
|
|
||||||
|
"DicomWeb": {
|
||||||
|
"Enable": true,
|
||||||
|
"Root": "/dicom-web/",
|
||||||
|
"EnableWado": true,
|
||||||
|
"WadoRoot": "/wado",
|
||||||
|
"Host": "127.0.0.1",
|
||||||
|
"Ssl": false,
|
||||||
|
"StowMaxInstances": 10,
|
||||||
|
"StowMaxSize": 10,
|
||||||
|
"QidoCaseSensitive": false
|
||||||
|
}
|
||||||
|
}
|
||||||
26
docker/Nginx-Orthanc/docker-compose.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
version: '3.5'
|
||||||
|
|
||||||
|
services:
|
||||||
|
proxy:
|
||||||
|
image: nginx:1.15-alpine
|
||||||
|
ports:
|
||||||
|
- 8899:80
|
||||||
|
volumes:
|
||||||
|
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# LINK: https://hub.docker.com/r/jodogne/orthanc-plugins/
|
||||||
|
# TODO: Update to use Postgres
|
||||||
|
# https://github.com/mrts/docker-postgresql-multiple-databases
|
||||||
|
orthanc:
|
||||||
|
image: jodogne/orthanc-plugins:1.5.6
|
||||||
|
hostname: orthanc
|
||||||
|
volumes:
|
||||||
|
# Config
|
||||||
|
- ./config/orthanc.json:/etc/orthanc/orthanc.json:ro
|
||||||
|
# Persist data
|
||||||
|
- ./volumes/orthanc-db/:/var/lib/orthanc/db/
|
||||||
|
# ports:
|
||||||
|
# - '4242:4242' # DICOM
|
||||||
|
# - '8042:8042' # Web
|
||||||
|
restart: unless-stopped
|
||||||
0
docker/Nginx-Orthanc/volumes/orthanc-db/.githold
Normal file
2
docker/Nginx-Orthanc/volumes/orthanc-db/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
16
docker/OpenResty-Orthanc-Keycloak/.dockerignore
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Output
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Root
|
||||||
|
README.md
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
# Misc. Config
|
||||||
|
.git
|
||||||
|
.DS_Store
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
.circleci
|
||||||
5
docker/OpenResty-Orthanc-Keycloak/.env
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Docker ENV and ARG Variables
|
||||||
|
# ----------------------------
|
||||||
|
# https://vsupalov.com/docker-arg-env-variable-guide/
|
||||||
|
#
|
||||||
|
#
|
||||||
31
docker/OpenResty-Orthanc-Keycloak/README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Guide
|
||||||
|
|
||||||
|
Build docker container using:
|
||||||
|
|
||||||
|
- Build: `docker build -t authproxy .`
|
||||||
|
- Tag: `docker tag authproxy:latest authproxy:staging`
|
||||||
|
|
||||||
|
> Start your docker container, and volume mount the directory containing the
|
||||||
|
> `nginx-keycloak.conf` configuration file. We also mount the current directory
|
||||||
|
> under `/usr/share/nginx/html` so any html files in the current directory will
|
||||||
|
> be hosted behind the authenticating proxy. Finally, we mapped port 80 on the
|
||||||
|
> host to port 80 in the container.
|
||||||
|
|
||||||
|
`docker run -d -it -p 80:80 -v $PWD/:/config -v /:/usr/share/nginx/html authproxy -c /config/nginx.conf`
|
||||||
|
docker run -d -it -p 80:80 -v /:/config -v /:/usr/share/nginx/html authproxy -c
|
||||||
|
/config/nginx-keycloak.conf
|
||||||
|
|
||||||
|
## Orthanc
|
||||||
|
|
||||||
|
- Configuration
|
||||||
|
- http://book.orthanc-server.com/users/configuration.html#configuration
|
||||||
|
|
||||||
|
## Keycloak
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
Library we use to manage OpenID-Connect `implicit` flow:
|
||||||
|
https://github.com/maxmantz/redux-oidc
|
||||||
|
|
||||||
|
- Set admin user/pass in `docker-compose`
|
||||||
|
- What are realms?
|
||||||
259
docker/OpenResty-Orthanc-Keycloak/config/nginx.conf
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
worker_processes 2;
|
||||||
|
error_log /var/logs/nginx/mydomain.error.log;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
include /usr/share/nginx/modules/*.conf; # See /usr/share/doc/nginx/README.dynamic.
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024; ## Default: 1024
|
||||||
|
use epoll; # http://nginx.org/en/docs/events.html
|
||||||
|
multi_accept on; # http://nginx.org/en/docs/ngx_core_module.html#multi_accept
|
||||||
|
}
|
||||||
|
|
||||||
|
# Core Modules Docs:
|
||||||
|
# http://nginx.org/en/docs/http/ngx_http_core_module.html
|
||||||
|
http {
|
||||||
|
include '/usr/local/openresty/nginx/conf/mime.types';
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
keepalive_requests 100000;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
|
||||||
|
# lua_ settings
|
||||||
|
#
|
||||||
|
lua_package_path '/usr/local/openresty/lualib/?.lua;;';
|
||||||
|
lua_shared_dict discovery 1m; # cache for discovery metadata documents
|
||||||
|
lua_shared_dict jwks 1m; # cache for JWKs
|
||||||
|
# lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||||
|
|
||||||
|
variables_hash_max_size 2048;
|
||||||
|
server_names_hash_bucket_size 128;
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
resolver 8.8.8.8 valid=30s ipv6=off;
|
||||||
|
resolver_timeout 11s;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
# No idea what this is doing
|
||||||
|
# https://stackoverflow.com/a/5877989/1867984
|
||||||
|
# upstream upstream_server {
|
||||||
|
# # server 10.100.4.200:1010 max_fails=3 fail_timeout=30s;
|
||||||
|
# server 127.0.0.1:
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Nginx `listener` block
|
||||||
|
server {
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
listen 80;
|
||||||
|
# listen 443 ssl;
|
||||||
|
access_log /var/logs/nginx/mydomain.access.log;
|
||||||
|
|
||||||
|
# Domain to protect
|
||||||
|
server_name 127.0.0.1 localhost; # mydomain.com;
|
||||||
|
proxy_intercept_errors off;
|
||||||
|
# ssl_certificate /etc/letsencrypt/live/mydomain.co.uk/fullchain.pem;
|
||||||
|
# ssl_certificate_key /etc/letsencrypt/live/mydomain.co.uk/privkey.pem;
|
||||||
|
gzip on;
|
||||||
|
gzip_types text/css application/javascript application/json image/svg+xml;
|
||||||
|
gzip_comp_level 9;
|
||||||
|
etag on;
|
||||||
|
|
||||||
|
# https://github.com/bungle/lua-resty-session/issues/15
|
||||||
|
set $session_check_ssi off;
|
||||||
|
lua_code_cache off;
|
||||||
|
set $session_secret Eeko7aeb6iu5Wohch9Loo1aitha0ahd1;
|
||||||
|
set $session_storage cookie;
|
||||||
|
|
||||||
|
server_tokens off; # Hides server version num
|
||||||
|
|
||||||
|
# [PROTECTED] Reverse Proxy for `orthanc` admin
|
||||||
|
#
|
||||||
|
location /pacs-admin/ {
|
||||||
|
access_by_lua_block {
|
||||||
|
local opts = {
|
||||||
|
redirect_uri = "http://127.0.0.1/pacs-admin/admin",
|
||||||
|
discovery = "http://127.0.0.1/auth/realms/ohif/.well-known/openid-configuration",
|
||||||
|
token_endpoint_auth_method = "client_secret_basic",
|
||||||
|
client_id = "pacs",
|
||||||
|
client_secret = "66279641-eba6-47f5-9fdb-70c4ac74d548",
|
||||||
|
client_jwt_assertion_expires_in = 60 * 60,
|
||||||
|
ssl_verify = "no",
|
||||||
|
scope = "openid email profile",
|
||||||
|
refresh_session_interval = 900,
|
||||||
|
redirect_uri_scheme = "http",
|
||||||
|
redirect_after_logout_uri = "/",
|
||||||
|
session_contents = {id_token=true}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- call authenticate for OpenID Connect user authentication
|
||||||
|
local res, err = require("resty.openidc").authenticate(opts)
|
||||||
|
|
||||||
|
if err or not res then
|
||||||
|
ngx.print(err)
|
||||||
|
ngx.status = 200
|
||||||
|
ngx.say(err and err or "no access_token provided")
|
||||||
|
ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Or set cookie?
|
||||||
|
-- ngx.req.set_header("Authorization", "Bearer " .. res.access_token)
|
||||||
|
ngx.req.set_header("X-USER", res.id_token.sub)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
expires 0;
|
||||||
|
add_header Cache-Control private;
|
||||||
|
|
||||||
|
proxy_pass http://orthanc:8042/;
|
||||||
|
}
|
||||||
|
|
||||||
|
# [PROTECTED] Reverse Proxy for `orthanc` APIs (including DICOMWeb)
|
||||||
|
#
|
||||||
|
location /pacs/ {
|
||||||
|
access_by_lua_block {
|
||||||
|
local opts = {
|
||||||
|
discovery = "http://127.0.0.1/auth/realms/ohif/.well-known/openid-configuration",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- call bearer_jwt_verify for OAuth 2.0 JWT validation
|
||||||
|
local res, err = require("resty.openidc").bearer_jwt_verify(opts)
|
||||||
|
|
||||||
|
if err or not res then
|
||||||
|
ngx.status = 403
|
||||||
|
ngx.say(err and err or "no access_token provided")
|
||||||
|
ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
# proxy_set_header Upgrade $http_upgrade;
|
||||||
|
# proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
expires 0;
|
||||||
|
add_header Cache-Control private;
|
||||||
|
|
||||||
|
proxy_pass http://orthanc:8042/;
|
||||||
|
|
||||||
|
# By default, this endpoint is protected by CORS (cross-origin-resource-sharing)
|
||||||
|
# You can add headers to allow other domains to request this resource.
|
||||||
|
# See the "Updating CORS Settings" example below
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keycloak
|
||||||
|
#
|
||||||
|
location /auth/ {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
|
||||||
|
proxy_pass http://keycloak:8080/auth/;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Do not cache sw.js, required for offline-first updates.
|
||||||
|
location /sw.js {
|
||||||
|
add_header Cache-Control "no-cache";
|
||||||
|
proxy_cache_bypass $http_pragma;
|
||||||
|
proxy_cache_revalidate on;
|
||||||
|
expires off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Single Page App
|
||||||
|
# Try files, fallback to index.html
|
||||||
|
#
|
||||||
|
location / {
|
||||||
|
alias /var/www/html/;
|
||||||
|
index index.html;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||||
|
}
|
||||||
|
|
||||||
|
# EXAMPLE: Reverse Proxy, no auth
|
||||||
|
# [UNPROTECTED] reverse proxy for `orthanc`
|
||||||
|
#
|
||||||
|
# location /pacs/ {
|
||||||
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
#
|
||||||
|
# proxy_pass http://orthanc:8042/;
|
||||||
|
#
|
||||||
|
# # OR
|
||||||
|
# # rewrite ^/pacs(.*) /$1 break;
|
||||||
|
# # proxy_pass http://orthanc:8042;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# EXAMPLE: Modifying headers to allow requests from other domains
|
||||||
|
# IE. Updating CORS settings
|
||||||
|
#
|
||||||
|
# location / {
|
||||||
|
# if ($request_method = 'OPTIONS') {
|
||||||
|
# add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
# add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||||
|
# #
|
||||||
|
# # Custom headers and headers various browsers *should* be OK with but aren't
|
||||||
|
# #
|
||||||
|
# add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
||||||
|
# #
|
||||||
|
# # Tell client that this pre-flight info is valid for 20 days
|
||||||
|
# #
|
||||||
|
# add_header 'Access-Control-Allow-Headers' 'Authorization';
|
||||||
|
# add_header 'Access-Control-Allow-Credentials' true;
|
||||||
|
# add_header 'Access-Control-Max-Age' 1728000;
|
||||||
|
# add_header 'Content-Length' 0;
|
||||||
|
# return 204;
|
||||||
|
# }
|
||||||
|
# if ($request_method = 'POST') {
|
||||||
|
# add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
# add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||||
|
# add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
||||||
|
# add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
|
||||||
|
# }
|
||||||
|
# if ($request_method = 'GET') {
|
||||||
|
# add_header 'Access-Control-Allow-Origin' '*';
|
||||||
|
# add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||||
|
# add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
|
||||||
|
# add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
|
||||||
|
# add_header 'Access-Control-Allow-Headers' 'Authorization';
|
||||||
|
# add_header 'Access-Control-Allow-Credentials' true;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# # proxy_http_version 1.1;
|
||||||
|
#
|
||||||
|
# # proxy_set_header Host $host;
|
||||||
|
# # proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# # proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
#
|
||||||
|
# proxy_pass http://orthanc:8042;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# EXAMPLE: Redirect server error pages to the static page /40x.html
|
||||||
|
#
|
||||||
|
# error_page 404 /404.html;
|
||||||
|
# location = /40x.html {
|
||||||
|
# }
|
||||||
|
|
||||||
|
# EXAMPLE: Redirect server error pages to the static page /50x.html
|
||||||
|
#
|
||||||
|
# error_page 500 502 503 504 /50x.html;
|
||||||
|
# location = /50x.html {
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
}
|
||||||
1876
docker/OpenResty-Orthanc-Keycloak/config/ohif-keycloak-realm.json
Normal file
89
docker/OpenResty-Orthanc-Keycloak/config/orthanc.json
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"Name": "Orthanc inside Docker",
|
||||||
|
"StorageDirectory": "/var/lib/orthanc/db",
|
||||||
|
"IndexDirectory": "/var/lib/orthanc/db",
|
||||||
|
"StorageCompression": false,
|
||||||
|
"MaximumStorageSize": 0,
|
||||||
|
"MaximumPatientCount": 0,
|
||||||
|
"LuaScripts": [],
|
||||||
|
"Plugins": ["/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"],
|
||||||
|
"ConcurrentJobs": 2,
|
||||||
|
"HttpServerEnabled": true,
|
||||||
|
"HttpPort": 8042,
|
||||||
|
"HttpDescribeErrors": true,
|
||||||
|
"HttpCompressionEnabled": true,
|
||||||
|
"DicomServerEnabled": true,
|
||||||
|
"DicomAet": "ORTHANC",
|
||||||
|
"DicomCheckCalledAet": false,
|
||||||
|
"DicomPort": 4242,
|
||||||
|
"DefaultEncoding": "Latin1",
|
||||||
|
"DeflatedTransferSyntaxAccepted": true,
|
||||||
|
"JpegTransferSyntaxAccepted": true,
|
||||||
|
"Jpeg2000TransferSyntaxAccepted": true,
|
||||||
|
"JpegLosslessTransferSyntaxAccepted": true,
|
||||||
|
"JpipTransferSyntaxAccepted": true,
|
||||||
|
"Mpeg2TransferSyntaxAccepted": true,
|
||||||
|
"RleTransferSyntaxAccepted": true,
|
||||||
|
"UnknownSopClassAccepted": false,
|
||||||
|
"DicomScpTimeout": 30,
|
||||||
|
|
||||||
|
"RemoteAccessAllowed": true,
|
||||||
|
"SslEnabled": false,
|
||||||
|
"SslCertificate": "certificate.pem",
|
||||||
|
"AuthenticationEnabled": false,
|
||||||
|
"RegisteredUsers": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"DicomModalities": {},
|
||||||
|
"DicomModalitiesInDatabase": false,
|
||||||
|
"DicomAlwaysAllowEcho": true,
|
||||||
|
"DicomAlwaysAllowStore": true,
|
||||||
|
"DicomCheckModalityHost": false,
|
||||||
|
"DicomScuTimeout": 10,
|
||||||
|
"OrthancPeers": {},
|
||||||
|
"OrthancPeersInDatabase": false,
|
||||||
|
"HttpProxy": "",
|
||||||
|
|
||||||
|
"HttpVerbose": true,
|
||||||
|
|
||||||
|
"HttpTimeout": 10,
|
||||||
|
"HttpsVerifyPeers": true,
|
||||||
|
"HttpsCACertificates": "",
|
||||||
|
"UserMetadata": {},
|
||||||
|
"UserContentType": {},
|
||||||
|
"StableAge": 60,
|
||||||
|
"StrictAetComparison": false,
|
||||||
|
"StoreMD5ForAttachments": true,
|
||||||
|
"LimitFindResults": 0,
|
||||||
|
"LimitFindInstances": 0,
|
||||||
|
"LimitJobs": 10,
|
||||||
|
"LogExportedResources": false,
|
||||||
|
"KeepAlive": true,
|
||||||
|
"TcpNoDelay": true,
|
||||||
|
"HttpThreadsCount": 50,
|
||||||
|
"StoreDicom": true,
|
||||||
|
"DicomAssociationCloseDelay": 5,
|
||||||
|
"QueryRetrieveSize": 10,
|
||||||
|
"CaseSensitivePN": false,
|
||||||
|
"LoadPrivateDictionary": true,
|
||||||
|
"Dictionary": {},
|
||||||
|
"SynchronousCMove": true,
|
||||||
|
"JobsHistorySize": 10,
|
||||||
|
"SaveJobs": true,
|
||||||
|
"OverwriteInstances": false,
|
||||||
|
"MediaArchiveSize": 1,
|
||||||
|
"StorageAccessOnFind": "Always",
|
||||||
|
"MetricsEnabled": true,
|
||||||
|
|
||||||
|
"DicomWeb": {
|
||||||
|
"Enable": true,
|
||||||
|
"Root": "/dicom-web/",
|
||||||
|
"EnableWado": true,
|
||||||
|
"WadoRoot": "/wado",
|
||||||
|
"Host": "127.0.0.1",
|
||||||
|
"Ssl": false,
|
||||||
|
"StowMaxInstances": 10,
|
||||||
|
"StowMaxSize": 10,
|
||||||
|
"QidoCaseSensitive": false
|
||||||
|
}
|
||||||
|
}
|
||||||
95
docker/OpenResty-Orthanc-Keycloak/docker-compose.yml
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# Reference:
|
||||||
|
# - https://docs.docker.com/compose/compose-file
|
||||||
|
# - https://eclipsesource.com/blogs/2018/01/11/authenticating-reverse-proxy-with-keycloak/
|
||||||
|
|
||||||
|
version: '3.5'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Exposed server that's handling incoming web requests
|
||||||
|
# Underlying image: openresty/openresty:alpine-fat
|
||||||
|
ohif_viewer:
|
||||||
|
build:
|
||||||
|
# Project root
|
||||||
|
context: ./../../
|
||||||
|
# Relative to context
|
||||||
|
dockerfile: ./docker/OpenResty-Orthanc-Keycloak/dockerfile
|
||||||
|
image: webapp:latest
|
||||||
|
container_name: webapp
|
||||||
|
volumes:
|
||||||
|
# Nginx config
|
||||||
|
- ./config/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro
|
||||||
|
# Logs
|
||||||
|
- ./logs/nginx:/var/logs/nginx
|
||||||
|
# Let's Encrypt
|
||||||
|
# - letsencrypt_certificates:/etc/letsencrypt
|
||||||
|
# - letsencrypt_challenges:/var/www/letsencrypt
|
||||||
|
ports:
|
||||||
|
- '443:443' # SSL
|
||||||
|
- '80:80' # Web
|
||||||
|
depends_on:
|
||||||
|
- keycloak
|
||||||
|
- orthanc
|
||||||
|
restart: on-failure
|
||||||
|
|
||||||
|
# LINK: https://hub.docker.com/r/jodogne/orthanc-plugins/
|
||||||
|
# TODO: Update to use Postgres
|
||||||
|
# https://github.com/mrts/docker-postgresql-multiple-databases
|
||||||
|
orthanc:
|
||||||
|
image: jodogne/orthanc-plugins:1.5.6
|
||||||
|
hostname: orthanc
|
||||||
|
container_name: orthanc
|
||||||
|
volumes:
|
||||||
|
# Config
|
||||||
|
- ./config/orthanc.json:/etc/orthanc/orthanc.json:ro
|
||||||
|
# Persist data
|
||||||
|
- ./volumes/orthanc-db/:/var/lib/orthanc/db/
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# LINK: https://hub.docker.com/r/jboss/keycloak
|
||||||
|
keycloak:
|
||||||
|
image: jboss/keycloak:6.0.1
|
||||||
|
hostname: keycloak
|
||||||
|
container_name: keycloak
|
||||||
|
volumes:
|
||||||
|
# Theme: https://www.keycloak.org/docs/latest/server_development/index.html#_themes
|
||||||
|
- ./volumes/keycloak-themes/ohif:/opt/jboss/keycloak/themes/ohif
|
||||||
|
# Previous Realm Config
|
||||||
|
- ./config/ohif-keycloak-realm.json:/tmp/ohif-keycloak-realm.json
|
||||||
|
environment:
|
||||||
|
# Database
|
||||||
|
DB_VENDOR: postgres
|
||||||
|
DB_ADDR: postgres
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_DATABASE: keycloak
|
||||||
|
DB_SCHEMA: public
|
||||||
|
DB_USER: keycloak
|
||||||
|
DB_PASSWORD: password
|
||||||
|
# Keycloak
|
||||||
|
KEYCLOAK_USER: admin
|
||||||
|
KEYCLOAK_PASSWORD: password
|
||||||
|
KEYCLOAK_IMPORT: /tmp/ohif-keycloak-realm.json
|
||||||
|
# KEYCLOAK_WELCOME_THEME: <theme-name>
|
||||||
|
# KEYCLOAK_DEFAULT_THEME: <theme-name>
|
||||||
|
# KEYCLOAK_HOSTNAME: (recommended in prod)
|
||||||
|
# KEYCLOAK_LOGLEVEL: DEBUG
|
||||||
|
PROXY_ADDRESS_FORWARDING: 'true'
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# LINK: https://hub.docker.com/_/postgres/
|
||||||
|
postgres:
|
||||||
|
image: postgres:11.2
|
||||||
|
hostname: postgres
|
||||||
|
container_name: postgres
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: keycloak
|
||||||
|
POSTGRES_USER: keycloak
|
||||||
|
POSTGRES_PASSWORD: password
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
driver: local
|
||||||
65
docker/OpenResty-Orthanc-Keycloak/dockerfile
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# docker-compose
|
||||||
|
# --------------
|
||||||
|
# This dockerfile is used by the `docker-compose.yml` adjacent file. When
|
||||||
|
# running `docker-compose build`, this dockerfile helps build the "webapp" image.
|
||||||
|
# All paths are relative to the `context`, which is the project root directory.
|
||||||
|
#
|
||||||
|
# docker build
|
||||||
|
# --------------
|
||||||
|
# If you would like to use this dockerfile to build and tag an image, make sure
|
||||||
|
# you set the context to the project's root directory:
|
||||||
|
# https://docs.docker.com/engine/reference/commandline/build/
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# SUMMARY
|
||||||
|
# --------------
|
||||||
|
# This dockerfile has two stages:
|
||||||
|
#
|
||||||
|
# 1. Building the React application for production
|
||||||
|
# 2. Setting up our Nginx (OpenResty*) image w/ step one's output
|
||||||
|
#
|
||||||
|
# * OpenResty is functionally identical to Nginx with the addition of Lua out of
|
||||||
|
# the box.
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 1: Build the application
|
||||||
|
FROM node:11.2.0-slim as builder
|
||||||
|
|
||||||
|
RUN mkdir /usr/src/app
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
ENV REACT_APP_CONFIG=config/docker_openresty-orthanc-keycloak.js
|
||||||
|
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
||||||
|
|
||||||
|
COPY package.json /usr/src/app/package.json
|
||||||
|
COPY yarn.lock /usr/src/app/yarn.lock
|
||||||
|
|
||||||
|
ADD . /usr/src/app/
|
||||||
|
RUN yarn install
|
||||||
|
RUN yarn run build:web
|
||||||
|
|
||||||
|
# Stage 2: Bundle the built application into a Docker container
|
||||||
|
# which runs openresty (nginx) using Alpine Linux
|
||||||
|
# LINK: https://hub.docker.com/r/openresty/openresty
|
||||||
|
FROM openresty/openresty:1.15.8.1rc1-0-alpine-fat
|
||||||
|
|
||||||
|
RUN mkdir /var/log/nginx
|
||||||
|
RUN apk add --no-cache openssl
|
||||||
|
RUN apk add --no-cache openssl-dev
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
RUN apk add --no-cache gcc
|
||||||
|
# !!!
|
||||||
|
RUN luarocks install lua-resty-openidc
|
||||||
|
|
||||||
|
#
|
||||||
|
RUN luarocks install lua-resty-jwt
|
||||||
|
RUN luarocks install lua-resty-session
|
||||||
|
RUN luarocks install lua-resty-http
|
||||||
|
# !!!
|
||||||
|
RUN luarocks install lua-resty-openidc
|
||||||
|
RUN luarocks install luacrypto
|
||||||
|
|
||||||
|
# Copy build output to image
|
||||||
|
COPY --from=builder /usr/src/app/build /var/www/html
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/openresty/nginx/sbin/nginx", "-g", "daemon off;"]
|
||||||
@ -0,0 +1,212 @@
|
|||||||
|
body {
|
||||||
|
background-color: #040507;
|
||||||
|
background-image: url('../img/background.jpg');
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
color: #fff;
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-shadow: 0px 0px 10px #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 20%;
|
||||||
|
left: 50%;
|
||||||
|
width: 550px;
|
||||||
|
margin-left: -180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-form {
|
||||||
|
float: left;
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-form label {
|
||||||
|
display: block;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#info-area {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin-top: 40px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#info-area p {
|
||||||
|
margin-right: 30px;
|
||||||
|
display: inline;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='text'],
|
||||||
|
input[type='password'] {
|
||||||
|
color: #333;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: rgba(256, 256, 256, 0.7);
|
||||||
|
border: 0px solid rgba(0, 0, 0, 0.2);
|
||||||
|
box-shadow: inset 0 0 2px 2px rgba(0, 0, 0, 0.15);
|
||||||
|
padding: 10px;
|
||||||
|
width: 296px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='text']:hover,
|
||||||
|
input[type='password']:hover {
|
||||||
|
background-color: rgba(256, 256, 256, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='submit'] {
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
background: -webkit-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
);
|
||||||
|
background: -moz-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
);
|
||||||
|
background: -ms-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
);
|
||||||
|
background: -o-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
);
|
||||||
|
|
||||||
|
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.5);
|
||||||
|
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='submit']:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-form-options div {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-form-options div label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-feedback {
|
||||||
|
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.5);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-feedback-wrapper {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.feedback-success {
|
||||||
|
background-color: rgba(155, 155, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.feedback-warning {
|
||||||
|
background-color: rgba(255, 175, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.feedback-error {
|
||||||
|
background-color: rgba(255, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-registration {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#social-login {
|
||||||
|
border-left: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
float: right;
|
||||||
|
width: 150px;
|
||||||
|
padding: 20px 0 200px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.social-login span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-social-providers ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-social-providers ul li {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#kc-social-providers ul li span {
|
||||||
|
display: inline;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.zocial {
|
||||||
|
border: none;
|
||||||
|
background: -webkit-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
) !important;
|
||||||
|
background: -moz-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
) !important;
|
||||||
|
background: -ms-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
) !important;
|
||||||
|
background: -o-linear-gradient(
|
||||||
|
top,
|
||||||
|
rgba(255, 255, 255, 0.8),
|
||||||
|
rgba(255, 255, 255, 0.1)
|
||||||
|
) !important;
|
||||||
|
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.5);
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
width: 130px;
|
||||||
|
text-shadow: none;
|
||||||
|
-webkit-border-radius: 0;
|
||||||
|
-moz-border-radius: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
padding-top: 0.2em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 3.0 MiB |
@ -0,0 +1,3 @@
|
|||||||
|
parent=base
|
||||||
|
import=common/keycloak
|
||||||
|
styles=lib/zocial/zocial.css css/styles.css
|
||||||
2
docker/OpenResty-Orthanc-Keycloak/volumes/orthanc-db/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
@ -1,39 +0,0 @@
|
|||||||
# docker-compose:
|
|
||||||
# https://docs.docker.com/compose/overview/
|
|
||||||
|
|
||||||
version: '3.5'
|
|
||||||
|
|
||||||
services:
|
|
||||||
orthanc:
|
|
||||||
container_name: orthanc
|
|
||||||
image: jodogne/orthanc-plugins
|
|
||||||
volumes:
|
|
||||||
- ../sampledata:/sampledata
|
|
||||||
ports:
|
|
||||||
- '4242:4242'
|
|
||||||
- '8042:8042'
|
|
||||||
restart: always
|
|
||||||
viewer:
|
|
||||||
container_name: ohif-viewer
|
|
||||||
build:
|
|
||||||
# Up to the root directory
|
|
||||||
context: ../
|
|
||||||
# Use our dockerfile to build the viewer
|
|
||||||
dockerfile: dockerfile
|
|
||||||
ports:
|
|
||||||
- '80:80'
|
|
||||||
depends_on:
|
|
||||||
- orthanc
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- REACT_APP_CONFIG=config/local_orthanc.js
|
|
||||||
restart: always
|
|
||||||
volumes:
|
|
||||||
- ../config/local_orthanc.js:/usr/share/nginx/html/servers.js
|
|
||||||
proxy:
|
|
||||||
image: nginx
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- 8899:80
|
|
||||||
volumes:
|
|
||||||
- ./nginx-proxy/conf/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"apps" : [{
|
|
||||||
"name" : "ohif-viewer",
|
|
||||||
"script" : "main.js",
|
|
||||||
"watch" : true,
|
|
||||||
"merge_logs" : true,
|
|
||||||
"cwd" : "/app/bundle/",
|
|
||||||
"env": {
|
|
||||||
"METEOR_SETTINGS": {
|
|
||||||
"servers": {
|
|
||||||
"dicomWeb": [
|
|
||||||
{
|
|
||||||
"name": "Orthanc",
|
|
||||||
"wadoUriRoot": "http://pacsIP:8042/wado",
|
|
||||||
"qidoRoot": "http://pacsIP:8042/dicom-web",
|
|
||||||
"wadoRoot": "http://pacsIP:8042/dicom-web",
|
|
||||||
"qidoSupportsIncludeField": false,
|
|
||||||
"imageRendering": "wadouri",
|
|
||||||
"thumbnailRendering": "wadouri",
|
|
||||||
"requestOptions": {
|
|
||||||
"auth": "orthanc:orthanc",
|
|
||||||
"logRequests": true,
|
|
||||||
"logResponses": false,
|
|
||||||
"logTiming": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"defaultServiceType": "dicomWeb",
|
|
||||||
"public": {
|
|
||||||
"ui": {
|
|
||||||
"studyListDateFilterNumDays": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"proxy": {
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"servers": {
|
|
||||||
"dicomWeb": [
|
|
||||||
{
|
|
||||||
"name": "Orthanc",
|
|
||||||
"wadoUriRoot": "http://pacsIP:8042/wado",
|
|
||||||
"qidoRoot": "http://pacsIP:8042/dicom-web",
|
|
||||||
"wadoRoot": "http://pacsIP:8042/dicom-web",
|
|
||||||
"qidoSupportsIncludeField": false,
|
|
||||||
"imageRendering": "wadouri",
|
|
||||||
"thumbnailRendering": "wadouri",
|
|
||||||
"requestOptions": {
|
|
||||||
"auth": "orthanc:orthanc",
|
|
||||||
"logRequests": true,
|
|
||||||
"logResponses": false,
|
|
||||||
"logTiming": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"defaultServiceType": "dicomWeb",
|
|
||||||
"public": {
|
|
||||||
"ui": {
|
|
||||||
"studyListDateFilterNumDays": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"proxy": {
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,44 @@
|
|||||||
##### Looking for your Deploy Preview? - <a onclick="function redirect() { window.location.href='/demo/'; } redirect();">Deploy Preview for Viewer</a>
|
##### Looking for a Deploy Preview? - <a onclick="function redirect() { window.location.href='/demo/'; } redirect();">Deploy Preview for Viewer</a>
|
||||||
|
|
||||||
# Introduction - test
|
> ATTENTION! You are looking at the docs for the `React` version of the OHIF
|
||||||
|
> Viewer. If you're looking for the `Meteor` version's documentation (now
|
||||||
|
> deprecated), select it's version from the dropdown box in the top left corner
|
||||||
|
> of this page.
|
||||||
|
|
||||||
The [Open Health Imaging Foundation](https://www.ohif.org) is developing an open source framework for constructing web-based medical imaging applications.
|
# Introduction
|
||||||
|
|
||||||
## The **OHIF Viewer**: A general purpose DICOM Viewer ([demo](http://viewer.ohif.org/))
|
The [Open Health Imaging Foundation][ohif-org] (OHIF) Viewer is an open source,
|
||||||
|
web-based, medical imaging viewer. It can be configured to connect to Image
|
||||||
|
Archives that support [DicomWeb][dicom-web], and offers support for mapping to
|
||||||
|
proprietary API formats. OHIF maintained extensions add support for viewing,
|
||||||
|
annotating, and reporting on DICOM images in 2D (slices) and 3D (volumes).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The Open Health Imaging Foundation intends to provide a simple general purpose DICOM Viewer which can be easily extended for specific uses.
|
<center><i>The <strong>OHIF Viewer</strong>: A general purpose DICOM Viewer (<a href="http://viewer.ohif.org/">Live Demo</a>)</center>
|
||||||
|
|
||||||
|
The Open Health Imaging Foundation intends to provide a simple general purpose
|
||||||
|
DICOM Viewer which can be easily extended for specific uses. If you find
|
||||||
|
yourself unable to extend the viewer for your purposes, please reach out via our
|
||||||
|
[GitHub issues][gh-issues]. We are actively seeking feedback on ways to improve
|
||||||
|
our integration and extension points.
|
||||||
|
|
||||||
|
## Where to Next?
|
||||||
|
|
||||||
|
Check out these helpful links:
|
||||||
|
|
||||||
|
- Ready to dive into some code? Check out our
|
||||||
|
[Getting Started Guide](./essentials/getting-started.md).
|
||||||
|
- We're an active, vibrant community.
|
||||||
|
[Learn how you can be more involved.](./contributing.md)
|
||||||
|
- Feeling lost? Read our [help page](./help.md).
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Links
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
[ohif-org]: https://www.ohif.org
|
||||||
|
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
|
||||||
|
[gh-issues]: https://github.com/OHIF/Viewers/issues
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
- Essentials
|
- Essentials
|
||||||
- [Getting Started](essentials/getting-started.md)
|
- [Getting Started](essentials/getting-started.md)
|
||||||
|
- [Data Source](essentials/data-source.md)
|
||||||
- [Configuration](essentials/configuration.md)
|
- [Configuration](essentials/configuration.md)
|
||||||
- [Themeing](essentials/themeing.md)
|
- [Themeing](essentials/themeing.md)
|
||||||
- [Troubleshooting](essentials/troubleshooting.md)
|
- [Troubleshooting](essentials/troubleshooting.md)
|
||||||
@ -41,11 +42,8 @@
|
|||||||
- Stand-Alone
|
- Stand-Alone
|
||||||
- [Build for Production](deployment/recipes/build-for-production.md)
|
- [Build for Production](deployment/recipes/build-for-production.md)
|
||||||
- [Static](deployment/recipes/static-assets.md)
|
- [Static](deployment/recipes/static-assets.md)
|
||||||
- [Docker]()
|
- [Nginx + Image Archive](deployment/recipes/nginx--image-archive.md)
|
||||||
- [Nginx + Orthanc]()
|
- [User Account Control](deployment/recipes/user-account-control.md)
|
||||||
- [Nginx + dcm4chee]()
|
|
||||||
- [Nginx + DICOMCloud]()
|
|
||||||
- [User Access Control]()
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 818 B After Width: | Height: | Size: 818 B |
|
Before Width: | Height: | Size: 473 B After Width: | Height: | Size: 473 B |
BIN
docs/latest/assets/designs/user-access-control-request-flow.fig
Normal file
BIN
docs/latest/assets/img/jwt-explained.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
docs/latest/assets/img/keycloak-default-theme.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
docs/latest/assets/img/keycloak-ohif-theme.png
Normal file
|
After Width: | Height: | Size: 884 KiB |
BIN
docs/latest/assets/img/user-access-control-request-flow.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
@ -0,0 +1,4 @@
|
|||||||
|
<div style="text-align: center;">
|
||||||
|
<img src="/assets/img/user-access-control-request-flow.png" alt="request flow example" style="margin: 0 auto;" />
|
||||||
|
<div><i>simplified request flow diagram</i></div>
|
||||||
|
</div>
|
||||||
1
docs/latest/deployment/recipes/nginx--image-archive.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Nginx + Image Archive
|
||||||
289
docs/latest/deployment/recipes/user-account-control.md
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
# User Account Control
|
||||||
|
|
||||||
|
> DISCLAIMER! We make no claims or guarantees of this approach's security. If in
|
||||||
|
> doubt, enlist the help of an expert and conduct proper audits.
|
||||||
|
|
||||||
|
Making a viewer and its medical imaging data accessible on the open web can
|
||||||
|
provide a lot of benefits, but requires additional security to make sure
|
||||||
|
sensitive information can only be viewed by authorized individuals. Most image
|
||||||
|
archives are equipped with basic security measures, but they are not
|
||||||
|
robust/secure enough for the open web.
|
||||||
|
|
||||||
|
This guide covers one of many potential production setups that secure our
|
||||||
|
sensitive data.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide builds on top of our
|
||||||
|
[Nginx + Image Archive guide](/deployment/recipes/nginx--image-archive.md),
|
||||||
|
wherein we used a [`reverse proxy`](https://en.wikipedia.org/wiki/Reverse_proxy)
|
||||||
|
to retrieve resources from our image archive (Orthanc).
|
||||||
|
|
||||||
|
To add support for "User Account Control" we introduce
|
||||||
|
[Keycloak](https://www.keycloak.org/about.html). Keycloak is an open source
|
||||||
|
Identity and Access Management solution that makes it easy to secure
|
||||||
|
applications and services with little to no code. We improve upon our
|
||||||
|
`reverse proxy` setup by integrating Keycloak and Nginx to create an
|
||||||
|
`authenticating reverse proxy`.
|
||||||
|
|
||||||
|
> An authenticating reverse proxy is a reverse proxy that only retrieves the
|
||||||
|
> resources on behalf of a client if the client has been authenticated. If a
|
||||||
|
> client is not authenticated they can be redirected to a login page.
|
||||||
|
|
||||||
|
This setup allows us to create a setup similar to the one pictured below:
|
||||||
|
|
||||||
|
{% include "./../_user-account-control-flow-diagram.md" %}
|
||||||
|
|
||||||
|
- All web requests are routed through `nginx` on our `OpenResty` image
|
||||||
|
- `/pacs` is a reverse proxy for `orthanc`'s `DICOM Web` endpoints
|
||||||
|
- Requires valid `Authorization: Bearer <token>` header
|
||||||
|
- `/pacs-admin` is a reverse proxy for `orthanc`'s Web Admin
|
||||||
|
- `/auth` is a reverse proxy for `keycloak`
|
||||||
|
- All static resources for OHIF Viewer are unprotected and accessible. We have
|
||||||
|
application logic that will redirect unauthenticated users to the appropriate
|
||||||
|
`keycloak` login screen.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Docker
|
||||||
|
- [Docker for Mac](https://docs.docker.com/docker-for-mac/)
|
||||||
|
- [Docker for Windows](https://docs.docker.com/docker-for-windows/)
|
||||||
|
|
||||||
|
_Not sure if you have `docker` installed already? Try running `docker --version`
|
||||||
|
in command prompt or terminal_
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
_Spin Things Up_
|
||||||
|
|
||||||
|
- Navigate to `<project-root>/docker/OpenResty-Orthanc-Keycloak` in your shell
|
||||||
|
- Run `docker-compose up`
|
||||||
|
|
||||||
|
_Create Your First User_
|
||||||
|
|
||||||
|
- Navigate to: `http://127.0.0.1/auth/admin`
|
||||||
|
- Sign in with: `admin`/`password`
|
||||||
|
- From the top left dropdown, select the `Ohif` realm
|
||||||
|
- From the left sidebar, under `Manage`, select `Users`
|
||||||
|
- Click `Add User`
|
||||||
|
- Username: `test`
|
||||||
|
- Email Verified: `ON`
|
||||||
|
- Click `Save`
|
||||||
|
- Click the `Credentials` Tab
|
||||||
|
- New Pasword: `test`
|
||||||
|
- Password Confirmation: `test`
|
||||||
|
- Temporary: `OFF`
|
||||||
|
- Click: `Reset Password`
|
||||||
|
- From the top right dropdown, select `Admin`, then `Sign Out`
|
||||||
|
|
||||||
|
_Sign In_
|
||||||
|
|
||||||
|
- Navigate to `http://127.0.0.1/`
|
||||||
|
- Username: `test`, Password: `test`
|
||||||
|
- Click `Log In`
|
||||||
|
|
||||||
|
_Upload Your First Study_
|
||||||
|
|
||||||
|
- Navigate to `http://127.0.0.1/pacs-admin`
|
||||||
|
- If you're not already logged in, use `test`/`test`
|
||||||
|
- From the top right, select "Upload"
|
||||||
|
- Click "Select files to upload..." (DICOM)
|
||||||
|
- Click "Start the upload"
|
||||||
|
- Navigate back to `http://127.0.0.1/` to view your studies in the Study List
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
_Exit code 137_
|
||||||
|
|
||||||
|
This means Docker ran out of memory. Open Docker Desktop, go to the `advanced`
|
||||||
|
tab, and increase the amount of Memory available.
|
||||||
|
|
||||||
|
_Cannot create container for service X_
|
||||||
|
|
||||||
|
Use this one with caution: `docker system prune`
|
||||||
|
|
||||||
|
_X is already running_
|
||||||
|
|
||||||
|
Stop running all containers:
|
||||||
|
|
||||||
|
- Win: `docker ps -a -q | ForEach { docker stop $_ }`
|
||||||
|
- Linux: `docker stop $(docker ps -a -q)`
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
After verifying that everything runs with default configuration values, you will
|
||||||
|
likely want to update:
|
||||||
|
|
||||||
|
- The domain: `http://127.0.0.1`
|
||||||
|
- Set secure, non-default passwords
|
||||||
|
- Regenerate Keycloak Client Secrets
|
||||||
|
|
||||||
|
#### OHIF Viewer
|
||||||
|
|
||||||
|
The OHIF Viewer's configuration is imported from a static `.js` file and made
|
||||||
|
available globally at `window.config`. The configuration we use is set to a
|
||||||
|
specific file when we build the viewer, and determined by the env variable:
|
||||||
|
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
|
||||||
|
this solution:
|
||||||
|
|
||||||
|
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc-keycloak.js`
|
||||||
|
|
||||||
|
You can find the configuration we're using here:
|
||||||
|
`/public/config/docker_openresty-orthanc-keycloak.js`
|
||||||
|
|
||||||
|
To rebuild the `webapp` image created by our `dockerfile` after updating the
|
||||||
|
Viewer's configuration, you can run:
|
||||||
|
|
||||||
|
- `docker-compose build` OR
|
||||||
|
- `docker-compose up --build`
|
||||||
|
|
||||||
|
#### Other
|
||||||
|
|
||||||
|
All other files are found in: `/docker/OpenResty-Orthanc-Keycloak/`
|
||||||
|
|
||||||
|
| Service | Configuration | Docs |
|
||||||
|
| ----------------- | ------------------------------------------------ | ------------------------------------------- |
|
||||||
|
| OHIF Viewer | [dockerfile][dockerfile] / [config.js][config] | You're reading them now! |
|
||||||
|
| OpenResty (Nginx) | [`/nginx.conf`][config-nginx] | [lua-resty-openidc][lua-resty-openidc-docs] |
|
||||||
|
| Orthanc | [`/orthanc.json`][config-orthanc] | [Here][orthanc-docs] |
|
||||||
|
| Keycloak | [`/ohif-keycloak-realm.json`][config-keycloak]\* | |
|
||||||
|
|
||||||
|
- \* These are the seed values for Keycloak. They can be manually updated at
|
||||||
|
`http://127.0.0.1/auth/admin`
|
||||||
|
|
||||||
|
#### Keycloak Themeing
|
||||||
|
|
||||||
|
The `Login` screen for the `ohif-viewer` client is using a Custom Keycloak
|
||||||
|
theme. You can find the source files for it in
|
||||||
|
`/docker/OpenResty-Orthanc-Keycloak/volumes/keycloak-themes/`. You can see how
|
||||||
|
we add it to Keycloak in the `docker-compose` file, and you can read up on how
|
||||||
|
to leverage custom themes in
|
||||||
|
[Keycloak's own docs](https://www.keycloak.org/docs/latest/server_development/index.html#_themes).
|
||||||
|
|
||||||
|
| Default Theme | OHIF Theme |
|
||||||
|
| ---------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
||||||
|
|  |  |
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
### Deploying to Production
|
||||||
|
|
||||||
|
While these configuration and docker-compose files model an environment suitable
|
||||||
|
for production, they are not easy to deploy "as is". You can either:
|
||||||
|
|
||||||
|
- Manually recreate this environment and deploy built application files **OR**
|
||||||
|
- Deploy to a cloud kubernetes provider like
|
||||||
|
[Digital Ocean](https://www.digitalocean.com/products/kubernetes/) **OR**
|
||||||
|
- [See a full list of cloud providers here](https://landscape.cncf.io/category=cloud&format=card-mode&grouping=category)
|
||||||
|
- Find and follow your preferred provider's guide on setting up
|
||||||
|
[swarms and stacks](https://docs.docker.com/get-started/)
|
||||||
|
|
||||||
|
### Adding SSL
|
||||||
|
|
||||||
|
Adding SSL registration and renewal for your domain with Let's Encrypt that
|
||||||
|
terminates at Nginx is an incredibly important step toward securing your data.
|
||||||
|
Here are some resources, specific to this setup, that may be helpful:
|
||||||
|
|
||||||
|
- [lua-resty-auto-ssl](https://github.com/GUI/lua-resty-auto-ssl)
|
||||||
|
- [Let's Encrypt + Nginx](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/)
|
||||||
|
|
||||||
|
While we terminate SSL at Nginx, it may be worth using self signed certificates
|
||||||
|
for communication between services.
|
||||||
|
|
||||||
|
- [SSL Termination for TCP Upstream Servers](https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/)
|
||||||
|
|
||||||
|
### Use PostgresSQL w/ Orthanc
|
||||||
|
|
||||||
|
Orthanc can handle a large amount of data and requests, but if you find that
|
||||||
|
requests start to slow as you add more and more studies, you may want to
|
||||||
|
configure your Orthanc instance to use PostgresSQL. Instructions on how to do
|
||||||
|
that can be found in the
|
||||||
|
[`Orthanc Server Book`](http://book.orthanc-server.com/users/docker.html), under
|
||||||
|
"PostgreSQL and Orthanc inside Docker"
|
||||||
|
|
||||||
|
### Improving This Guide
|
||||||
|
|
||||||
|
Here are some improvements this guide would benefit from, and that we would be
|
||||||
|
more than happy to accept Pull Requests for:
|
||||||
|
|
||||||
|
- SSL Support
|
||||||
|
- Complete configuration with `.env` file (or something similar)
|
||||||
|
- Keycloak Theme improvements
|
||||||
|
- Any security issues
|
||||||
|
- One-click deploy to a cloud provider
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
### Misc. Helpful Commands
|
||||||
|
|
||||||
|
_Check if `nginx.conf` is valid:_
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -t -a stdout --name my-openresty -v $PWD/config/:/usr/local/openresty/nginx/conf/:ro openresty/openresty:alpine-fat openresty -c /usr/local/openresty/nginx/conf/nginx.conf -t
|
||||||
|
```
|
||||||
|
|
||||||
|
_Interact w/ running container:_
|
||||||
|
|
||||||
|
`docker exec -it CONTAINER_NAME bash`
|
||||||
|
|
||||||
|
_List running containers:_
|
||||||
|
|
||||||
|
`docker ps`
|
||||||
|
|
||||||
|
_Clear Keycloak DB so you can re-seed values:_
|
||||||
|
|
||||||
|
- `docker volume prune` OR
|
||||||
|
- `docker volume ls` and `docker volume rm VOLUME_NAME VOLUME_NAME`
|
||||||
|
|
||||||
|
### Referenced Articles
|
||||||
|
|
||||||
|
The inspiration for our setup was driven largely by these articles:
|
||||||
|
|
||||||
|
- [Securing Nginx with Keycloak](https://edhull.co.uk/blog/2018-06-06/keycloak-nginx)
|
||||||
|
- [Authenticating Reverse Proxy with Keycloak](https://eclipsesource.com/blogs/2018/01/11/authenticating-reverse-proxy-with-keycloak/)
|
||||||
|
- [Securing APIs with Kong and Keycloak](https://www.jerney.io/secure-apis-kong-keycloak-1/)
|
||||||
|
|
||||||
|
For more documentation on the software we've chosen to use, you may find the
|
||||||
|
following resources helpful:
|
||||||
|
|
||||||
|
- [Orthanc for Docker](http://book.orthanc-server.com/users/docker.html)
|
||||||
|
- [OpenResty Guide](http://www.staticshin.com/programming/definitely-an-open-resty-guide/)
|
||||||
|
- [Lua Ngx API](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/)
|
||||||
|
- [Auth0: Picking a Grant Type](https://auth0.com/docs/api-auth/which-oauth-flow-to-use)
|
||||||
|
|
||||||
|
We chose to use a generic OpenID Connect library on the client, but it's worth
|
||||||
|
noting that Keycloak comes packaged with its own:
|
||||||
|
|
||||||
|
- [redux-oidc](https://github.com/maxmantz/redux-oidc) (Which wraps
|
||||||
|
[oidc-client-js](https://github.com/IdentityModel/oidc-client-js/wiki))
|
||||||
|
- [Keycloak JavaScript Adapter](https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter)
|
||||||
|
|
||||||
|
If you're not already drowning in links, here are some good security resources
|
||||||
|
for OAuth:
|
||||||
|
|
||||||
|
- [Diagrams of OpenID Connect Flows](https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660)
|
||||||
|
- [KeyCloak: OpenID Connect Flows](https://www.keycloak.org/docs/latest/securing_apps/index.html#authorization-code)
|
||||||
|
- [Good description on SSO Protocols](https://www.keycloak.org/docs/2.5/server_admin/topics/sso-protocols/oidc.html)
|
||||||
|
|
||||||
|
For a different take on this setup, check out the repository one of our
|
||||||
|
community members put together:
|
||||||
|
|
||||||
|
- [mjstealey/ohif-orthanc-dimse-docker](https://github.com/mjstealey/ohif-orthanc-dimse-docker)
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Links
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
<!-- DOCS -->
|
||||||
|
[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
|
||||||
|
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc
|
||||||
|
<!-- SRC -->
|
||||||
|
[config]: #
|
||||||
|
[dockerfile]: #
|
||||||
|
[config-nginx]: #
|
||||||
|
[config-orthanc]: #
|
||||||
|
[config-keycloak]: #
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
@ -2,14 +2,25 @@
|
|||||||
|
|
||||||
The ohif-viewer package provides two different build processes:
|
The ohif-viewer package provides two different build processes:
|
||||||
|
|
||||||
# create-react-app
|
## create-react-app
|
||||||
|
|
||||||
> [create-react-app](https://github.com/facebook/create-react-app) provides pre-configured build process for developing front-end applications with [React](https://reactjs.org/).
|
> [create-react-app](https://github.com/facebook/create-react-app) provides
|
||||||
|
> pre-configured build process for developing front-end applications with
|
||||||
|
> [React](https://reactjs.org/).
|
||||||
|
|
||||||
The ohif-viewer package can be run as a create-react-app application. This is useful for development, debugging, or evolving ohif-viewer into your own custom imaging application.
|
The ohif-viewer package can be run as a create-react-app application. This is
|
||||||
|
useful for development, debugging, or evolving ohif-viewer into your own custom
|
||||||
|
imaging application.
|
||||||
|
|
||||||
# Rollup
|
## Rollup
|
||||||
|
|
||||||
> [Rollup](https://rollupjs.org/guide/en) is a module bundler for JavaScript. It uses the new standardized format for code modules included in the ES6 revision of JavaScript.
|
> [Rollup](https://rollupjs.org/guide/en) is a module bundler for JavaScript. It
|
||||||
|
> uses the new standardized format for code modules included in the ES6 revision
|
||||||
|
> of JavaScript.
|
||||||
|
|
||||||
The ohif-viewer package can be built with Rollup to provide a set of React components which can be dropped into a larger application. Specifically, the ohif-viewer package provides a React component named `OHIFViewer` which is the entire viewer, configurable via React `props`. This is useful for including the OHIF Viewer in a larger web application, as the entire application can be provided via a `<script>` tag with no build process required.
|
The ohif-viewer package can be built with Rollup to provide a set of React
|
||||||
|
components which can be dropped into a larger application. Specifically, the
|
||||||
|
ohif-viewer package provides a React component named `OHIFViewer` which is the
|
||||||
|
entire viewer, configurable via React `props`. This is useful for including the
|
||||||
|
OHIF Viewer in a larger web application, as the entire application can be
|
||||||
|
provided via a `<script>` tag with no build process required.
|
||||||
|
|||||||
122
docs/latest/essentials/data-source.md
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
# Data Source
|
||||||
|
|
||||||
|
After following the steps outlined in [Getting Started](./getting-started.md),
|
||||||
|
you'll notice that the OHIF Viewer has data for several studies and their
|
||||||
|
images. You didn't add this data, so where is it coming from?
|
||||||
|
|
||||||
|
By default, the viewer is configured to connect to a remote server hosted by the
|
||||||
|
nice folks over at [dcmjs.org][dcmjs-org]. While convenient for getting started,
|
||||||
|
the time may come when you want to develop using your own data either locally or
|
||||||
|
remotely.
|
||||||
|
|
||||||
|
## Set up a local DICOM server
|
||||||
|
|
||||||
|
> ATTENTION! Already have a remote or local server? Skip to the
|
||||||
|
> [configuration section](#configuration-learn-more) below.
|
||||||
|
|
||||||
|
While the OHIF Viewer can work with any data source, the easiest to configure
|
||||||
|
are the ones that follow the [DICOMWeb][dicom-web] spec.
|
||||||
|
|
||||||
|
1. Choose and install an Image Archive
|
||||||
|
2. Upload data to your archive (e.g. with DCMTK's [storescu][storescu] or your
|
||||||
|
archive's web interface)
|
||||||
|
3. Keep the server running
|
||||||
|
|
||||||
|
For our purposes, we will be using `Orthanc`, but you can see a list of
|
||||||
|
[other Open Source options](#open-source-dicom-image-archives) below.
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
### Running Orthanc
|
||||||
|
|
||||||
|
_Start Orthanc:_
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Runs orthanc so long as window remains open
|
||||||
|
yarn run orthanc:up
|
||||||
|
```
|
||||||
|
|
||||||
|
_Upload your first Study:_
|
||||||
|
|
||||||
|
1. Navigate to [Orthanc's web interface](http://localhost:8899) at
|
||||||
|
`http://localhost:8899` in a web browser.
|
||||||
|
2. In the top right corner, click "Upload"
|
||||||
|
3. Click "Select files to upload..." and select one or more DICOM files
|
||||||
|
4. Click "Start the upload"
|
||||||
|
|
||||||
|
#### Orthanc: Learn More
|
||||||
|
|
||||||
|
You can see the `docker-compose.yml` file this command runs at
|
||||||
|
[`<project-root>/docker/Nginx-Docker/`](#), and more on Orthanc for Docker in
|
||||||
|
[Orthanc's documentation][orthanc-docker].
|
||||||
|
|
||||||
|
### Connecting to Orthanc
|
||||||
|
|
||||||
|
Now that we have a local Orthanc instance up and running, we need to configure
|
||||||
|
our web application to connect to it. Open a new terminal window, navigate to
|
||||||
|
this project's root directory, and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# If you haven't already, restore dependencies
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# Run our dev command, but with the local orthanc config
|
||||||
|
yarn run dev:orthanc
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Configuration: Learn More
|
||||||
|
|
||||||
|
> For more configuration fun, check out the
|
||||||
|
> [Essentials Configuration](./configuration.md) guide.
|
||||||
|
|
||||||
|
Let's take a look at what's going on under the hood here. `yarn run dev:orthanc`
|
||||||
|
is running the `dev:orthanc` script in our project's `package.json`. That script
|
||||||
|
is:
|
||||||
|
|
||||||
|
```js
|
||||||
|
cross-env PORT=5000 REACT_APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start
|
||||||
|
```
|
||||||
|
|
||||||
|
- `cross-env` sets two environment variables
|
||||||
|
- PORT: 5000
|
||||||
|
- REACT_APP_CONFIG: `config/docker_nginx-orthanc.js`
|
||||||
|
- `react-scripts` runs it's `start` script. This is [the de-facto
|
||||||
|
way][cra-start] to run a "Create React App" in development mode.
|
||||||
|
|
||||||
|
The `REACT_APP_CONFIG` value tells our app which file to load on to
|
||||||
|
`window.config`. By default, our app uses the file at
|
||||||
|
`<project-root>/public/config/default.js`.
|
||||||
|
|
||||||
|
## Open Source DICOM Image Archives
|
||||||
|
|
||||||
|
| Archive | Installation |
|
||||||
|
| --------------------------------------------- | ---------------------------------- |
|
||||||
|
| [DCM4CHEE Archive 5.x][dcm4chee] | [W/ Docker][dcm4chee-docker] |
|
||||||
|
| [Orthanc][orthanc] | [W/ Docker][orthanc-docker] |
|
||||||
|
| [DICOMcloud][dicomcloud] (**DICOM Web only**) | [Installation][dicomcloud-install] |
|
||||||
|
| [OsiriX][osirix] (**Mac OSX only**) | Desktop Client |
|
||||||
|
| [Horos][horos] (**Mac OSX only**) | Desktop Client |
|
||||||
|
|
||||||
|
_Feel free to make a Pull Request if you want to add to this list._
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Links
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
[dcmjs-org]: https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado
|
||||||
|
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
|
||||||
|
[storescu]: http://support.dcmtk.org/docs/storescu.html
|
||||||
|
[cra-start]: https://github.com/facebook/create-react-app#npm-start-or-yarn-start
|
||||||
|
<!-- Archives -->
|
||||||
|
[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
|
||||||
|
[dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
|
||||||
|
[orthanc]: https://www.orthanc-server.com/
|
||||||
|
[orthanc-docker]: http://book.orthanc-server.com/users/docker.html
|
||||||
|
[dicomcloud]: https://github.com/DICOMcloud/DICOMcloud
|
||||||
|
[dicomcloud-install]: https://github.com/DICOMcloud/DICOMcloud#running-the-code
|
||||||
|
[osirix]: http://www.osirix-viewer.com/
|
||||||
|
[horos]: https://www.horosproject.org/
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
@ -1,43 +1,59 @@
|
|||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
## Getting the Code
|
## Setup
|
||||||
|
|
||||||
Either clone the repository using Git:
|
### Fork & Clone
|
||||||
|
|
||||||
```bash
|
If you intend to contribute back changes, or if you would like to pull updates
|
||||||
git clone git@github.com:OHIF/Viewers.git
|
we make to the OHIF Viewer, then follow these steps:
|
||||||
```
|
|
||||||
|
- [Fork][fork-a-repo] the [OHIF/Viewers][ohif-viewers-repo] repository
|
||||||
or
|
- [Create a local clone][clone-a-repo] of your fork
|
||||||
[Download the latest Master as a ZIP File](https://github.com/OHIF/Viewers/archive/master.zip).
|
- `git clone https://github.com/YOUR-USERNAME/Viewers`
|
||||||
|
- Add OHIF/Viewers as a [remote repository][add-remote-repo] labled `upstream`
|
||||||
## Run the OHIF Viewer application against our public DICOM server
|
- Navigate to the cloned project's directory
|
||||||
|
- `git remote add upstream https://github.com/OHIF/Viewers.git`
|
||||||
You can either spin up locally or run with Docker.
|
|
||||||
|
With this setup, you can now [sync your fork][sync-changes] to keep it
|
||||||
### running locally
|
up-to-date with the upstream (original) repository. This is called a "Triangular
|
||||||
|
Workflow" and is common for Open Source projects. The GitHub blog has a [good
|
||||||
1. [Install Node.js](https://nodejs.org/en/)
|
graphic that illustrates this setup][triangular-workflow].
|
||||||
2. Open a new terminal tab, go under `ohif-viewer` directory and install all
|
|
||||||
dependency packages via `yarn`
|
### Private
|
||||||
|
|
||||||
|
Alternatively, if you intend to use the OHIF Viewer as a starting point, and you
|
||||||
|
aren't as concerned with syncing updates, then follow these steps:
|
||||||
|
|
||||||
|
1. Navigate to the [OHIF/Viewers/tree/react][ohif-viewers-react-repo] repository
|
||||||
|
and branch
|
||||||
|
2. Click `Clone or download`, and then `Download ZIP`
|
||||||
|
3. Use the contents of the `.zip` file as a starting point for your viewer
|
||||||
|
|
||||||
|
> NOTE: It is still possible to sync changes using this approach. However,
|
||||||
|
> submitting pull requests for fixes and features are best done with the
|
||||||
|
> separate, forked repository setup described in "Fork & Clone"
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- [Node.js & NPM](https://nodejs.org/en/)
|
||||||
|
- [Yarn](https://yarnpkg.com/en/)
|
||||||
|
|
||||||
|
### Kick the tires
|
||||||
|
|
||||||
|
Navigate to the root of the project's directory in your terminal and run the
|
||||||
|
following commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Restore dependencies
|
||||||
yarn install
|
yarn install
|
||||||
```
|
|
||||||
|
|
||||||
3. Run the application
|
# Start local development server
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn start
|
yarn start
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: This will connect to our public DICOMWeb server so you can verify your
|
You should see the following output:
|
||||||
installation. Follow the next section to connect to your own local or remote
|
|
||||||
DICOMWeb server.
|
|
||||||
|
|
||||||
4. Launch the OHIF Viewer Study List. By default the address is
|
|
||||||
[http://localhost:3000/](http://localhost:3000/). The port may vary so check
|
|
||||||
the start up output messages such as:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
Compiled successfully!
|
Compiled successfully!
|
||||||
@ -51,132 +67,49 @@ Note that the development build is not optimized.
|
|||||||
To create a production build, use yarn build.
|
To create a production build, use yarn build.
|
||||||
```
|
```
|
||||||
|
|
||||||
**If everything is working correctly, you should see the studies from our public
|
### 🎉 Celebrate 🎉
|
||||||
archive when you visit the Study List.**
|
|
||||||
|
|
||||||

|
<center>
|
||||||
|
<img alt="development server hosted app" src="/assets/img/loading-study.gif" />
|
||||||
|
<i>Our app, hosted by the development server</i>
|
||||||
|
</center>
|
||||||
|
|
||||||
5. Double-click on a Study in the Study List to launch it in the Viewer
|
### Building for Production
|
||||||
|
|
||||||
**If everything is working correctly, you should see your study load into the
|
> More comprehensive guides for building and publishing can be found in our
|
||||||
Viewer.**
|
> [deployment docs](./../deployment/index.md)
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Set up a local DICOM server
|
|
||||||
|
|
||||||
1. Choose and install an Image Archive
|
|
||||||
2. Upload some data into your archive (e.g. with DCMTK's
|
|
||||||
[storescu](http://support.dcmtk.org/docs/storescu.html) or your archive's web
|
|
||||||
interface)
|
|
||||||
3. Keep the server running
|
|
||||||
|
|
||||||
#### Open Source DICOM Image Archive Options
|
|
||||||
|
|
||||||
| Archive | Installation |
|
|
||||||
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
||||||
| [DCM4CHEE Archive 5.x](https://github.com/dcm4che/dcm4chee-arc-light) | [Installation with Docker](https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker) |
|
|
||||||
| [Orthanc](https://www.orthanc-server.com/) | [Installation with Docker](http://book.orthanc-server.com/users/docker.html) |
|
|
||||||
| [DICOMcloud](https://github.com/DICOMcloud/DICOMcloud) (**DICOM Web only**) | [Installation](https://github.com/DICOMcloud/DICOMcloud#running-the-code) |
|
|
||||||
| [OsiriX](http://www.osirix-viewer.com/) (**Mac OSX only**) |
|
|
||||||
| [Horos](https://www.horosproject.org/) (**Mac OSX only**) |
|
|
||||||
|
|
||||||
_Feel free to make a Pull Request if you want to add to this list._
|
|
||||||
|
|
||||||
#### Orthanc with Docker
|
|
||||||
|
|
||||||
Depending on whether or not you want uploaded studies to persist in Orthanc
|
|
||||||
after Docker has been closed, there are two different methods for starting the
|
|
||||||
Docker image:
|
|
||||||
|
|
||||||
##### Temporary data storage
|
|
||||||
|
|
||||||
This command will start an instance of the jodogne/orthanc-plugins Docker image.
|
|
||||||
_All data will be removed when the instance is stopped!_
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run --rm -p 4242:4242 -p 8042:8042 jodogne/orthanc-plugins
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Persistent data storage
|
|
||||||
|
|
||||||
In order to allow your data to persist after the instance is stopped, you first
|
|
||||||
need to create an image and attached data volume with Docker. The steps are as
|
|
||||||
follows:
|
|
||||||
|
|
||||||
1. Create a persistent data volume for Orthanc to use
|
|
||||||
|
|
||||||
```
|
|
||||||
docker create --name sampledata -v /sampledata jodogne/orthanc-plugins
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note: On Windows, you need to use an absolute path for the data volume,
|
|
||||||
like so:**
|
|
||||||
|
|
||||||
```
|
|
||||||
docker create --name sampledata -v '//C/Users/erik/sampledata' jodogne/orthanc-plugins
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Run Orthanc from Docker with the data volume attached
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run --volumes-from sampledata -p 4242:4242 -p 8042:8042 jodogne/orthanc-plugins
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Upload your data and it will be persisted
|
|
||||||
|
|
||||||
### Setting up OHIF Viewer with Orthanc as an example
|
|
||||||
|
|
||||||
Once you have Orthanc running with docker either with temporary data storage or
|
|
||||||
persistent data storage we con move forward with the next steps.
|
|
||||||
|
|
||||||
1. Load orthanc with a dataset you might want to use. To upload data use
|
|
||||||
[http://localhost:8042/app/explorer.html](http://localhost:8042/app/explorer.html).
|
|
||||||
|
|
||||||
**orthanc is the username and password for orthanc docker**
|
|
||||||
|
|
||||||
2. Go under
|
|
||||||
[http://localhost:8042/app/explorer.html#upload](http://localhost:8042/app/explorer.html#upload)
|
|
||||||
and upload your DICOM files there
|
|
||||||
|
|
||||||
3. After you load the data, open a new terminal tab in the `ohif-viewer`
|
|
||||||
directory and install all dependency packages via Yarn
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn install
|
# Build static assets to host a PWA
|
||||||
|
yarn run build:web
|
||||||
|
|
||||||
|
# Build packaged output
|
||||||
|
yarn run build:package
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Run the application using one of the available configuration files. **the
|
## Next Steps
|
||||||
following command assumes you are under the `root` folder**
|
|
||||||
|
|
||||||
```bash
|
...
|
||||||
export REACT_APP_CONFIG=$(cat ./config/local_orthanc.js)
|
|
||||||
yarn start
|
|
||||||
```
|
|
||||||
|
|
||||||
This uses the
|
## Troubleshooting
|
||||||
[Custom Environment Variables of Create-React-App](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables)
|
|
||||||
to pass in your configuration. The example above will not work on Windows.
|
|
||||||
Please visit the link to read about how to set environment variables on Windows.
|
|
||||||
|
|
||||||
4. Launch the OHIF Viewer Study List by visiting
|
|
||||||
[http://localhost:3000/](http://localhost:3000/) in a web browser.
|
|
||||||
|
|
||||||
**If everything is working correctly, you should see the Study List from your
|
|
||||||
archive when you visit the Study List.**
|
|
||||||
|
|
||||||
5. Double-click on a Study in the Study List to launch it in the Viewer
|
|
||||||
|
|
||||||
**If everything is working correctly, you should see your study load into the
|
|
||||||
Viewer.**
|
|
||||||
|
|
||||||
#### Troubleshooting
|
|
||||||
|
|
||||||
- If you receive a _"No Studies Found"_ message and do not see your studies, try
|
- If you receive a _"No Studies Found"_ message and do not see your studies, try
|
||||||
changing the Study Date filters to a wider range.
|
changing the Study Date filters to a wider range.
|
||||||
- If you see a 'Loading' message which never resolves, check your browser
|
- If you see a 'Loading' message which never resolves, check your browser
|
||||||
JavaScript console inside the Developer Tools to identify any errors.
|
JavaScript console inside the Developer Tools to identify any errors.
|
||||||
- If you receive `exit code 137`, increase the amount of memory available to
|
|
||||||
your docker instances.
|
|
||||||
- If you see any errors in your server console, check the
|
- If you see any errors in your server console, check the
|
||||||
[Troubleshooting](./troubleshooting.md) page for more in depth advice.
|
[Troubleshooting](./troubleshooting.md) page for more in depth advice.
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Links
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
[fork-a-repo]: https://help.github.com/en/articles/fork-a-repo
|
||||||
|
[clone-a-repo]: https://help.github.com/en/articles/fork-a-repo#step-2-create-a-local-clone-of-your-fork
|
||||||
|
[add-remote-repo]: https://help.github.com/en/articles/fork-a-repo#step-3-configure-git-to-sync-your-fork-with-the-original-spoon-knife-repository
|
||||||
|
[sync-changes]: https://help.github.com/en/articles/syncing-a-fork
|
||||||
|
[triangular-workflow]: https://github.blog/2015-07-29-git-2-5-including-multiple-worktrees-and-triangular-workflows/#improved-support-for-triangular-workflows
|
||||||
|
[ohif-viewers-repo]: https://github.com/OHIF/Viewers
|
||||||
|
[ohif-viewers-react-repo]: https://github.com/OHIF/Viewers/tree/react
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
# Meteor Packages
|
|
||||||
|
|
||||||
### Commands (*ohif-commands*)
|
|
||||||
### Core (*ohif-core*)
|
|
||||||
|
|
||||||
## Cornerstone Package (*ohif-cornerstone*)
|
|
||||||
|
|
||||||
This package contains a number of front-end libraries that help us build web-based medical imaging applications.
|
|
||||||
|
|
||||||
These are:
|
|
||||||
- [dicomParser](https://github.com/cornerstonejs/dicomParser):
|
|
||||||
A lightweight JavaScript library for parsing DICOM P10 byte streams in modern web browsers (IE10+), Node.js, and Meteor.
|
|
||||||
|
|
||||||
- [Cornerstone Core](https://github.com/cornerstonejs/cornerstone):
|
|
||||||
A lightweight JavaScript library for displaying medical images in modern web browsers that support the HTML5 canvas element.
|
|
||||||
|
|
||||||
- [Cornerstone Tools](https://github.com/cornerstonejs/cornerstoneTools):
|
|
||||||
A library built on top of cornerstone that provides a set of common tools needed in medical imaging to work with images and stacks of images
|
|
||||||
|
|
||||||
- [Cornerstone Math](https://github.com/cornerstonejs/cornerstoneMath):
|
|
||||||
Math and computational geometry functionality for Cornerstone
|
|
||||||
|
|
||||||
- [Cornerstone WADO Image Loader](https://github.com/cornerstonejs/cornerstoneWADOImageLoader):
|
|
||||||
A Cornerstone Image Loader for DICOM P10 instances over HTTP. This can be used to integrate cornerstone with WADO-URI servers or any other HTTP based server that returns DICOM P10 instances (e.g. Orthanc or custom servers).
|
|
||||||
|
|
||||||
- [Hammer.js](https://github.com/hammerjs/hammer.js):
|
|
||||||
A JavaScript library for multi-touch gestures
|
|
||||||
|
|
||||||
### Design (*ohif-design*)
|
|
||||||
### DICOM Services (*ohif-dicom-services*)
|
|
||||||
It contains a number of helper functions for retrieving common value types (e.g. JSON, patient name, image frame) from a DICOM image. This package is for server-side usage.
|
|
||||||
|
|
||||||
### Hanging Protocols (*ohif-hanging-protocols*)
|
|
||||||
### Header (*ohif-header*)
|
|
||||||
### Hotkeys (*ohif-hotkeys*)
|
|
||||||
|
|
||||||
### Lesion Tracker (*ohif-lesiontracker*)
|
|
||||||
This package stores all of the oncology-specific tools and functions developed for the Lesion Tracker application. Here we store, for example, the Target measurement and Non-target pointer tools that are used to monitor tumour burden over time.
|
|
||||||
|
|
||||||
This package also stores Meteor components for the interactive lesion table used in the Lesion Tracker, and dialog boxes for the callbacks attached to the Target and Non-target tools.
|
|
||||||
|
|
||||||
### Logging (*ohif-log*)
|
|
||||||
### Logging (*ohif-measurements*)
|
|
||||||
### Metadata (*ohif-metadata*)
|
|
||||||
### Polyfilling Functionality (*ohif-polyfill*)
|
|
||||||
|
|
||||||
### Select Tree UI (*ohif-select-tree*)
|
|
||||||
### Server Settings UI (*ohif-servers*)
|
|
||||||
### Studies (*ohif-studies*)
|
|
||||||
### Study List UI (*ohif-study-list*)
|
|
||||||
### Common Themes (*ohif-themes-common*)
|
|
||||||
### Theming (*ohif-themes*)
|
|
||||||
### User Management (*ohif-user-management*)
|
|
||||||
### User (*ohif-user*)
|
|
||||||
|
|
||||||
### Basic Viewer Components (*ohif-viewerbase*)
|
|
||||||
This is the largest package in the repository. It holds a large number of re-usable Meteor components that are used to build both the OHIF Viewer and Lesion Tracker.
|
|
||||||
|
|
||||||
### WADO Proxy (*ohif-wadoproxy*)
|
|
||||||
Proxy for CORS
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
# Orthanc with Docker
|
|
||||||
|
|
||||||
Depending on whether or not you want uploaded studies to persist in Orthanc after Docker has been closed, there are two different methods for starting the Docker image:
|
|
||||||
|
|
||||||
## Temporary data storage
|
|
||||||
This command will start an instance of the jodogne/orthanc-plugins Docker image. *All data will be removed when the instance is stopped!*
|
|
||||||
|
|
||||||
````
|
|
||||||
docker run --rm -p 4242:4242 -p 8042:8042 jodogne/orthanc-plugins
|
|
||||||
````
|
|
||||||
|
|
||||||
## Persistent data storage
|
|
||||||
In order to allow your data to persist after the instance is stopped, you first need to create an image and attached data volume with Docker. The steps are as follows:
|
|
||||||
|
|
||||||
1. Create a persistent data volume for Orthanc to use
|
|
||||||
|
|
||||||
````
|
|
||||||
docker create --name sampledata -v /sampledata jodogne/orthanc-plugins
|
|
||||||
````
|
|
||||||
|
|
||||||
**Note: On Windows, you need to use an absolute path for the data volume, like so:**
|
|
||||||
|
|
||||||
````
|
|
||||||
docker create --name sampledata -v '//C/Users/erik/sampledata' jodogne/orthanc-plugins
|
|
||||||
````
|
|
||||||
|
|
||||||
2. Run Orthanc from Docker with the data volume attached
|
|
||||||
|
|
||||||
````
|
|
||||||
docker run --volumes-from sampledata -p 4242:4242 -p 8042:8042 jodogne/orthanc-plugins
|
|
||||||
````
|
|
||||||
|
|
||||||
3. Upload your data and it will be persisted
|
|
||||||
@ -1 +1,59 @@
|
|||||||
# Themeing
|
# Themeing
|
||||||
|
|
||||||
|
Themeing is currently accomplished with color variables that are defined within
|
||||||
|
the [`:root`](https://css-tricks.com/almanac/selectors/r/root/) selector
|
||||||
|
(allowing them to cascade across all elements). This repository's components,
|
||||||
|
and the ones we consume from our
|
||||||
|
[React Viewerbase component library](https://react.ohif.org/styling-and-theming)
|
||||||
|
utilize them. We are interested in pursuing more robust themeing options, and
|
||||||
|
open to pull requests and discussion issues.
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
/* Interface UI Colors */
|
||||||
|
--default-color: #9ccef9;
|
||||||
|
--hover-color: #ffffff;
|
||||||
|
--active-color: #20a5d6;
|
||||||
|
--ui-border-color: #44626f;
|
||||||
|
--ui-border-color-dark: #3c5d80;
|
||||||
|
--ui-border-color-active: #00a4d9;
|
||||||
|
--primary-background-color: #000000;
|
||||||
|
--box-background-color: #3e5975;
|
||||||
|
|
||||||
|
--text-primary-color: #ffffff;
|
||||||
|
--text-secondary-color: #91b9cd;
|
||||||
|
--input-background-color: #2c363f;
|
||||||
|
--input-placeholder-color: #d3d3d3;
|
||||||
|
|
||||||
|
--table-hover-color: #2c363f;
|
||||||
|
--table-text-primary-color: #ffffff;
|
||||||
|
--table-text-secondary-color: #91b9cd;
|
||||||
|
|
||||||
|
--large-numbers-color: #6fbde2;
|
||||||
|
|
||||||
|
--state-error: #ffcccc;
|
||||||
|
--state-error-border: #ffcccc;
|
||||||
|
--state-error-text: #ffcccc;
|
||||||
|
|
||||||
|
/* Common palette */
|
||||||
|
--ui-yellow: #e29e4a;
|
||||||
|
--ui-sky-blue: #6fbde2;
|
||||||
|
|
||||||
|
/* State palette */
|
||||||
|
--ui-state-error: #ffcccc;
|
||||||
|
--ui-state-error-border: #993333;
|
||||||
|
--ui-state-error-text: #661111;
|
||||||
|
--ui-gray-lighter: #436270;
|
||||||
|
--ui-gray-light: #516873;
|
||||||
|
--ui-gray: #263340;
|
||||||
|
--ui-gray-dark: #16202b;
|
||||||
|
--ui-gray-darker: #151a1f;
|
||||||
|
--ui-gray-darkest: #14202a;
|
||||||
|
|
||||||
|
--calendar-day-color: #d3d3d3;
|
||||||
|
--calendar-day-border-color: #d3d3d3;
|
||||||
|
--calendar-day-active-hover-background-color: #516873;
|
||||||
|
--calendar-main-color: #263340;
|
||||||
|
--viewport-border-thickness: 1px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
# Common Problems
|
## Common Problems
|
||||||
|
|
||||||
Problem | Most Common Reasons
|
| Problem | Most Common Reasons |
|
||||||
--------|--------------------
|
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
** Can't retrieve Study List over DICOMWeb** | 1. QIDO root URL is incorrect<br> 2. DICOM Web is not enabled on PACS
|
| ** Can't retrieve Study List over DICOMWeb** | 1. QIDO root URL is incorrect<br> 2. DICOM Web is not enabled on PACS |
|
||||||
** Can't retrieve images** | 1. WADO Root URL is incorrect<br> 2. DICOM Web is not enabled on PACS<br> 3. HTTP Basic Authentication username and password are incorrect or not provided.
|
| ** Can't retrieve images** | 1. WADO Root URL is incorrect<br> 2. DICOM Web is not enabled on PACS<br> 3. HTTP Basic Authentication username and password are incorrect or not provided. |
|
||||||
|
|
||||||
|
## Debugging Steps
|
||||||
|
|
||||||
# Debugging Steps
|
|
||||||
### Can't retrieve Study List over DICOMWeb
|
### Can't retrieve Study List over DICOMWeb
|
||||||
|
|
||||||
1. Check that you can query your PACS using an alternative DICOM Web client (e.g. cURL, or a Web Browser). If you cannot, then your PACS is configured incorrectly. Refer to the documentation of the image archive.
|
1. Check that you can query your PACS using an alternative DICOM Web client
|
||||||
|
(e.g. cURL, or a Web Browser). If you cannot, then your PACS is configured
|
||||||
|
incorrectly. Refer to the documentation of the image archive.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 585 KiB |
|
Before Width: | Height: | Size: 227 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 733 KiB |
|
Before Width: | Height: | Size: 517 KiB |
|
Before Width: | Height: | Size: 424 KiB |
|
Before Width: | Height: | Size: 457 KiB |
|
Before Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 305 KiB |
|
Before Width: | Height: | Size: 315 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 595 KiB |
|
Before Width: | Height: | Size: 576 KiB |
|
Before Width: | Height: | Size: 411 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 320 KiB |
|
Before Width: | Height: | Size: 521 KiB |
|
Before Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 303 KiB |
|
Before Width: | Height: | Size: 292 KiB |
|
Before Width: | Height: | Size: 306 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 241 KiB |
|
Before Width: | Height: | Size: 314 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 40 KiB |