From 710c1038763dd0f10d80a10901b3fef083be53e3 Mon Sep 17 00:00:00 2001
From: Wolfgang Knopki <wolfgang.knopki@hft-stuttgart.de>
Date: Wed, 18 Nov 2020 12:08:07 +0100
Subject: [PATCH] added prefixes

---
 config/default.json                       | 10 ++--
 helpers/space-render.js                   |  4 +-
 public/javascripts/backend.js             |  8 ++-
 public/javascripts/spacedeck_account.js   |  8 +--
 public/javascripts/spacedeck_routes.js    | 72 +++++++++++------------
 public/javascripts/spacedeck_sections.js  |  2 +-
 public/javascripts/spacedeck_spaces.js    | 24 ++++----
 public/javascripts/spacedeck_users.js     | 10 ++--
 public/stylesheets/style.css              |  2 +-
 routes/api/spaces.js                      |  2 +-
 routes/root.js                            | 20 ++++---
 spacedeck.js                              |  2 +-
 styles/icon.scss                          |  2 +-
 views/partials/folders.html               | 12 ++--
 views/partials/tool/toolbar-elements.html |  4 +-
 views/spacedeck.ejs                       |  8 ++-
 16 files changed, 102 insertions(+), 88 deletions(-)

diff --git a/config/default.json b/config/default.json
index 768e5a2..20ceb4c 100644
--- a/config/default.json
+++ b/config/default.json
@@ -4,13 +4,15 @@
 
   "host": "::",
   "port": 9666,
-  "endpoint": "http://localhost/spacedeck/",
+  "endpoint": "http://localhost/spacedeck",
   "invite_code": "top-sekrit",
+  "api_endpoint": "http://localhost/spacedeck",
+  "prefix":"/spacedeck",
 
   "storage_region": "eu-central-1",
 
   "storage_bucket": "my_spacedeck_bucket",
-  "storage_cdn": "/storage",
+  "storage_cdn": "/spacedeck/storage",
   "storage_local_path": "./storage",
   "storage_local_db": "./database.sqlite",
 
@@ -31,8 +33,8 @@
   "mail_smtp_user": "your.smtp.user",
   "mail_smtp_pass": "your.secret.smtp.password",
 
-  "path" : "http://localhost:9666/saml/SSO",
+  "path" : "/saml/SSO",
   "entryPoint" : "https://transfer.hft-stuttgart.de/idp2/saml2/idp/SSOService.php",
   "issuer" : "spacedeck_local.m4lab.hft-stuttgart.de",
   "logoutUrl": "https://transfer.hft-stuttgart.de/idp2/saml2/idp/SingleLogoutService.php"
-}
+  }
diff --git a/helpers/space-render.js b/helpers/space-render.js
index 99164ef..bfc8c87 100644
--- a/helpers/space-render.js
+++ b/helpers/space-render.js
@@ -12,6 +12,8 @@ var template = fs.readFileSync("views/partials/space-isolated.html");
 
 var dom = cheerio.load(template);
 
+const config = require('config');
+
 var compiled_js = "";
 
 function emit(str,indent) {
@@ -140,7 +142,7 @@ function render_space_as_html(space, artifacts) {
   var style="html, body, #space { overflow: visible !important; }\n";
   style+=".wrapper { border: none !important; }\n";
 
-  h='<html>\n<head>\n<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,700,600,800,300|Montserrat:400,700|EB+Garamond|Vollkorn|Fire+Sans|Lato|Roboto|Source+Code+Pro|Ubuntu|Raleway|Playfair+Display|Crimson+Text" rel="stylesheet" type="text/css">\n<link type="text/css" rel="stylesheet" href="https://fast.fonts.net/cssapi/ee1a3484-4d98-4f9f-9f55-020a7b37f3c5.css"/>\n<link rel="stylesheet" href="/stylesheets/style.css"><style>'+style+'</style>\n</head>\n<body id="main">\n'+h+"\n</html>\n";
+  h='<html>\n<head>\n<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,700,600,800,300|Montserrat:400,700|EB+Garamond|Vollkorn|Fire+Sans|Lato|Roboto|Source+Code+Pro|Ubuntu|Raleway|Playfair+Display|Crimson+Text" rel="stylesheet" type="text/css">\n<link type="text/css" rel="stylesheet" href="https://fast.fonts.net/cssapi/ee1a3484-4d98-4f9f-9f55-020a7b37f3c5.css"/>\n<link rel="stylesheet" href="' + config.endpoint + '/stylesheets/style.css"><style>'+style+'</style>\n</head>\n<body id="main">\n'+h+"\n</html>\n";
 
   return h;
 }
diff --git a/public/javascripts/backend.js b/public/javascripts/backend.js
index 2eb76c3..0882dfe 100644
--- a/public/javascripts/backend.js
+++ b/public/javascripts/backend.js
@@ -48,7 +48,9 @@ function load_resource(method, path, data, on_success, on_error, on_progress) {
   }
 
   req.withCredentials = true;
-  req.open(method, api_endpoint+"/api"+path, true);
+  req.open(method, ENV.apiEndpoint+"/api"+path, true);
+  console.log(ENV);
+  //req.open(method, "http://localhost/spacedeck/api"+path, true);
 
   if (api_token) {
     req.setRequestHeader("X-Spacedeck-Auth", api_token);
@@ -59,7 +61,8 @@ function load_resource(method, path, data, on_success, on_error, on_progress) {
   if (channel_id) {
     req.setRequestHeader("X-Spacedeck-Channel", channel_id);
   }
-
+  console.log("filled request?")
+  console.log(req);
   try {
     if (data) {
       if (data.toString() == "[object File]") {
@@ -75,6 +78,7 @@ function load_resource(method, path, data, on_success, on_error, on_progress) {
         req.send(JSON.stringify(data));
       }
     } else {
+      console.log("reached sending stage without data");
       req.send();
     }
   } catch (e) {
diff --git a/public/javascripts/spacedeck_account.js b/public/javascripts/spacedeck_account.js
index 8c28b42..eb0163e 100644
--- a/public/javascripts/spacedeck_account.js
+++ b/public/javascripts/spacedeck_account.js
@@ -37,7 +37,7 @@ SpacedeckAccount = {
       this.user.prefs_language = lang;
       this.save_user(function() {
         window._spacedeck_location_change = true;
-        location.href="/spaces";
+        location.href=ENV.endpoint + "/spaces";
       }.bind(this));
     },
 
@@ -49,7 +49,7 @@ SpacedeckAccount = {
 
       save_user(this.user, function(user) {
         if (on_success) on_success();
-        else location.href="/spaces";
+        else location.href=ENV.endpoint + "/spaces";
 
       }.bind(this), function(xhr){
         console.error(xhr)
@@ -108,12 +108,12 @@ SpacedeckAccount = {
     confirm_account: function(token) {
       confirm_user(this.user, token, function(re) {
         smoke.alert(__("confirmed"), function() {
-          this.redirect_to("/spaces");
+          this.redirect_to(ENV.prefix+"/spaces");
         }.bind(this));
       }.bind(this), function(xhr) {
         console.error(xhr);
         alert(xhr.responseText);
-        this.redirect_to("/spaces");
+        this.redirect_to(ENV.prefix+"/spaces");
       }.bind(this));
     },
   }
diff --git a/public/javascripts/spacedeck_routes.js b/public/javascripts/spacedeck_routes.js
index 6796177..3c6cde0 100644
--- a/public/javascripts/spacedeck_routes.js
+++ b/public/javascripts/spacedeck_routes.js
@@ -11,7 +11,7 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/spaces/:id",
+          path: ENV.prefix+"/spaces/:id",
           handler: function(params, on_success) {
             this.load_space(params.id, on_success);
           }.bind(this)
@@ -20,7 +20,7 @@ var SpacedeckRoutes = {
       
       this.router.add([
         {
-          path: "/spacedeck/s/:hash",
+          path: ENV.prefix+"/s/:hash",
           handler: function(params, on_success) {
             var parts = params.hash.split("-");
             if (path.length > 0) {
@@ -35,10 +35,10 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/confirm/:token",
+          path: ENV.prefix+"/confirm/:token",
           handler: function(params) {
             if (!this.logged_in) {
-              this.redirect_to("/spacedeck/login");
+              this.redirect_to(ENV.prefix+"/login");
             } else {
               this.confirm_account(params.token);
             }
@@ -48,13 +48,13 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/password-confirm/:token",
+          path: ENV.prefix+"/password-confirm/:token",
           handler: function(params) {
 
             console.log(params.token);
 
             if (this.logged_in) {
-              this.redirect_to("/spacedeck/spaces");
+              this.redirect_to(ENV.prefix+"/spaces");
             } else {
               this.reset_token = params.token;
               this.active_view = "password-confirm";
@@ -66,7 +66,7 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/password-reset",
+          path: ENV.prefix+"/password-reset",
           handler: function(params, test) {
             if (this.logged_in) {
             } else {
@@ -78,20 +78,20 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/accept/:membership_id",
+          path: ENV.prefix+"/accept/:membership_id",
           handler: function(params, test) {
             if (this.logged_in) {
               var invitation_token = get_query_param("code");
               accept_invitation(params.membership_id, invitation_token , function(m) {
                 window._spacedeck_location_change = true;
-                location.href = "/spacedeck/spaces/"+m.space._id;
+                location.href = ENV.prefix+"/spaces/"+m.space._id;
               }.bind(this), function(xhr) {
                 smoke.alert("Error ("+xhr.status+")", function() {
-                  this.redirect_to("/spacedeck/spaces");
+                  this.redirect_to(ENV.prefix+"/spaces");
                 }.bind(this));
               }.bind(this));
             } else {
-              this.redirect_to("/spacedeck/login");
+              this.redirect_to(ENV.prefix+"/login");
             }
           }.bind(this)
         }
@@ -99,7 +99,7 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/signup",
+          path: ENV.prefix+"/signup",
           handler: function(params) {
             var invitation_token = get_query_param("code");
 
@@ -108,7 +108,7 @@ var SpacedeckRoutes = {
             }
             
             if (this.logged_in) {
-              this.redirect_to("/spacedeck/spaces");
+              this.redirect_to(ENV.prefix+"/spaces");
             } else {
               this.active_view = "signup";
             }
@@ -119,7 +119,7 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/login",
+          path: ENV.prefix+"/login",
           handler: function(params) {
             if (this.logged_in) {
               if(this.invitation_token) {
@@ -128,7 +128,7 @@ var SpacedeckRoutes = {
                   location.href = "spaces/"+m.space_id;
                 }.bind(this), function(xhr) { console.error(xhr); });
               } else {
-                this.redirect_to("/spacedeck/spaces");
+                this.redirect_to(ENV.prefix+"/spaces");
               }
             } else {
               this.active_view = "login";
@@ -143,14 +143,14 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/logout",
+          path: ENV.prefix+"/logout",
           handler: function(params) {
             if (this.logged_in) {
               this.logout(function(m) {
-                this.redirect_to("/spacedeck/login");
+                this.redirect_to(ENV.prefix+"/login");
               }.bind(this), function(xhr) { console.error(xhr); });
             } else {
-              this.redirect_to("/spacedeck/login");
+              this.redirect_to(ENV.prefix+"/login");
             }
           }.bind(this)
         }
@@ -158,17 +158,17 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/spaces",
+          path: ENV.prefix+"/spaces",
           handler: function(params) {
             if (!this.logged_in) {
               window._spacedeck_location_change = true;
-              location.href = "/spacedeck/login";
+              location.href = ENV.prefix+"/login";
             } else {
 
               if (this.logged_in && this.user.home_folder_id) {
                 this.load_space(this.user.home_folder_id);
               } else {
-                location.href = "/spacedeck/";
+                location.href = ENV.prefix+"/";
               }
 
             }
@@ -178,11 +178,11 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/account",
+          path: ENV.prefix+"/account",
           handler: function(params) {
             if (!this.logged_in) {
               window._spacedeck_location_change = true;
-              location.href = "/spacedeck/";
+              location.href = ENV.prefix+"/";
             } else {
               this.active_view = "account";
             }
@@ -193,11 +193,11 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/team",
+          path: ENV.prefix+"/team",
           handler: function(params) {
             if (!this.logged_in) {
               window._spacedeck_location_change = true;
-              location.href = "/spacedeck/";
+              location.href = ENV.prefix+"/";
             } else {
               this.active_view = "team";
               this.load_team();
@@ -208,13 +208,13 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/folders/:id",
+          path: ENV.prefix+"/folders/:id",
           handler: function(params) {
             this.load_space(params.id, null, function(xhr) {
               // on_error
 
               console.log("couldn't load folder: "+xhr.status);
-              this.redirect_to("/spacedeck/spaces", function(){});
+              this.redirect_to(ENV.prefix+"/spaces", function(){});
             }.bind(this));
           }.bind(this)
         }
@@ -223,27 +223,27 @@ var SpacedeckRoutes = {
 
       this.router.add([
         {
-          path: "/spacedeck/",
+          path: ENV.prefix+"/",
           handler: function(params) {
-            location.href = "/spacedeck/";
+            location.href = ENV.prefix+"/";
           }.bind(this)
         }
       ]);
       
       this.router.add([
         {
-          path: "/spacedeck/terms",
+          path: ENV.prefix+"/terms",
           handler: function(params) {
-            location.href = "/spacedeck/terms";
+            location.href = ENV.prefix+"/terms";
           }.bind(this)
         }
       ]);
       
       this.router.add([
         {
-          path: "/spacedeck/privacy",
+          path: ENV.prefix+"/privacy",
           handler: function(params) {
-            location.href = "/spacedeck/privacy";
+            location.href = ENV.prefix+"/privacy";
           }.bind(this)
         }
       ]);
@@ -253,7 +253,7 @@ var SpacedeckRoutes = {
     if (foundRoute) {
       foundRoute[0].handler(foundRoute[0].params, on_success);
     } else {
-      location.href = "/spacedeck/not_found";
+      location.href = ENV.prefix+"/not_found";
     }
   },
 
@@ -300,10 +300,10 @@ var SpacedeckRoutes = {
   },
 
   link_to_parent_folder: function(space_id) {
-    return "/spacedeck/folders/"+space_id;
+    return ENV.prefix+"/folders/"+space_id;
   },
 
   link_to_space: function(space) {
-    return "/spacedeck/"+space.space_type+"s/"+space._id;
+    return ENV.prefix+"/"+space.space_type+"s/"+space._id;
   }
 }
diff --git a/public/javascripts/spacedeck_sections.js b/public/javascripts/spacedeck_sections.js
index 540d0ae..4c27056 100644
--- a/public/javascripts/spacedeck_sections.js
+++ b/public/javascripts/spacedeck_sections.js
@@ -410,7 +410,7 @@ var SpacedeckSections = {
         query_string+="?spaceAuth="+space.edit_hash;
       }
 
-      return "background-image:url('/api/spaces/"+space._id+"/png"+query_string+"')";
+      return "background-image:url('"+ ENV.apiEndpoint +"/api/spaces/"+space._id+"/png"+query_string+"')";
     },
 
     reset_artifact_filters: function() {
diff --git a/public/javascripts/spacedeck_spaces.js b/public/javascripts/spacedeck_spaces.js
index f802efa..c474862 100644
--- a/public/javascripts/spacedeck_spaces.js
+++ b/public/javascripts/spacedeck_spaces.js
@@ -34,9 +34,9 @@ var SpacedeckSpaces = {
     remix_style: "",
     guest_signup_enabled: false,
     space_embed_html: "",
-    share_base: location.origin,
-    share_base_url: location.origin+"/spaces/",
-    share_base_url_enc: encodeURIComponent(location.origin+"/spaces/"),
+    share_base: ENV.webEndpoint,
+    share_base_url: ENV.webEndpoint+"/spaces/",
+    share_base_url_enc: encodeURIComponent(ENV.webEndpoint+"/spaces/"),
     social_bar: true,
     can_add_comment: false,
 
@@ -289,12 +289,12 @@ var SpacedeckSpaces = {
 
           if (xhr.status == 403) {
             if (!this.logged_in) {
-              this.redirect_to("/login?space_id="+space_id);
+              this.redirect_to(ENV.prefix+"/login?space_id="+space_id);
             } else {
-              this.redirect_to("/");
+              this.redirect_to(ENV.prefix+"/");
             }
           } else {
-            this.redirect_to("/not_found");
+            this.redirect_to(ENV.prefix+"/not_found");
             console.error(xhr);
           }
         }.bind(this));
@@ -430,7 +430,7 @@ var SpacedeckSpaces = {
       save_space(s, function(saved_space) {
         this.active_folder.children.push(saved_space);
         if (space_type != "folder") {
-          this.redirect_to("/"+saved_space.space_type+"s/"+saved_space._id, function(succ) {
+          this.redirect_to(ENV.prefix+"/"+saved_space.space_type+"s/"+saved_space._id, function(succ) {
           });
         } else {
           this.rename_folder(saved_space);
@@ -492,9 +492,9 @@ var SpacedeckSpaces = {
 
         delete_space(space, function() {
           if (space.parent_space_id){
-            this.redirect_to("/folders/"+space.parent_space_id, function(succ) {});
+            this.redirect_to(ENV.prefix+"/folders/"+space.parent_space_id, function(succ) {});
           } else {
-            this.redirect_to("/spaces", function(succ) {});
+            this.redirect_to(ENV.prefix+"/spaces", function(succ) {});
           }
 
           this.close_modal();
@@ -615,7 +615,7 @@ var SpacedeckSpaces = {
 
     download_space_as_pdf: function(space) {
       this.global_spinner = true;
-      get_resource("/spaces/" + space._id + "/pdf", function(o) {
+      get_resource(ENV.endpoint + "/spaces/" + space._id + "/pdf", function(o) {
         this.global_spinner = false;
         location.href = o.url;
       }.bind(this), function(xhr) {
@@ -627,7 +627,7 @@ var SpacedeckSpaces = {
     download_space_as_zip: function(space) {
       this.global_spinner = true;
 
-      get_resource("/spaces/" + space._id + "/zip", function(o) {
+      get_resource(ENV.endpoint + "/spaces/" + space._id + "/zip", function(o) {
        
         this.global_spinner = false; 
         location.href = o.url;
@@ -640,7 +640,7 @@ var SpacedeckSpaces = {
     
     download_space_as_list: function(space) {
       this.global_spinner = true;
-      location.href = "/api/spaces/" + space._id + "/list";
+      location.href = ENV.apiEndpoint + "/api/spaces/" + space._id + "/list";
     },
     
     toggle_follow_mode: function() {
diff --git a/public/javascripts/spacedeck_users.js b/public/javascripts/spacedeck_users.js
index 3efa13a..72f27e1 100644
--- a/public/javascripts/spacedeck_users.js
+++ b/public/javascripts/spacedeck_users.js
@@ -45,20 +45,20 @@ SpacedeckUsers = {
       this.load_user(function(user) {
         if (this.invitation_token) {
           accept_invitation(this.invitation_token, function(memberships){
-            this.redirect_to("/spaces/"+memberships.space_id);
+            this.redirect_to(ENV.prefix+"/spaces/"+memberships.space_id);
           }.bind(this), function(xhr){
             console.error(xhr);
             alert("Could not accept invitation. Maybe it was already accepted?");
-            this.redirect_to("/spaces");
+            this.redirect_to(ENV.prefix+"/spaces");
           }.bind(this));
         } else {
           if (on_success) {
             on_success(this.user);
           } else {
             if (get_query_param("space_id") && get_query_param("space_id").length==24) {
-              this.redirect_to("/spaces/"+get_query_param("space_id"));
+              this.redirect_to(ENV.prefix+"/spaces/"+get_query_param("space_id"));
             } else {
-              this.redirect_to("/spaces", function() {});
+              this.redirect_to(ENV.prefix+"/spaces", function() {});
             }
           }
         }
@@ -234,7 +234,7 @@ SpacedeckUsers = {
         api_token = null;
         this.user = {};
         this.active_content_type = "login";
-        this.redirect_to("/");
+        this.redirect_to(ENV.prefix+"/");
 
       }.bind(this));
     },
diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css
index 289e6a0..c1f17ef 100644
--- a/public/stylesheets/style.css
+++ b/public/stylesheets/style.css
@@ -5906,7 +5906,7 @@ select {
   background-repeat: no-repeat; }
 
 .icon-sd6 {
-  background-image: url(/images/sd6-icon-white.svg); }
+  background-image: url(../images/sd6-icon-white.svg); }
 
 .icon-bullet:before {
   content: "\2022"; }
diff --git a/routes/api/spaces.js b/routes/api/spaces.js
index a8b3a38..2952fb9 100644
--- a/routes/api/spaces.js
+++ b/routes/api/spaces.js
@@ -188,7 +188,7 @@ router.post('/', function(req, res, next) {
       attrs.access_mode = "private";
       
       db.Space.create(attrs).then(createdSpace => {
-        res.status(201).json(createdSpace);
+        //res.status(201).json(createdSpace);
         
         // create initial admin membership
         var membership = {
diff --git a/routes/root.js b/routes/root.js
index a7aa8ac..2ea02a5 100644
--- a/routes/root.js
+++ b/routes/root.js
@@ -37,6 +37,9 @@ const uuidv4 = require('uuid/v4');
       entryPoint: config.entryPoint,
       issuer: config.issuer,
       identifierFormat: null,
+      //skipRequestCompression: true,
+      //authnRequestBinding: "HTTP-POST",
+      //disableRequestACSUrl: true,
 
       validateInResponseTo: false,
       disableRequestedAuthnContext: true
@@ -57,12 +60,13 @@ const uuidv4 = require('uuid/v4');
   router.get('/saml/metadata',
     function(req, res) {
       res.type('application/xml');
-      var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync('/cert/certificate.pem', 'utf8'));
-      res.status(200).send(spMetadata);
+      //var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync('/cert/certificate.pem', 'utf8'));
+      var spMetadata = samlStrategy.generateServiceProviderMetadata();
+           res.status(200).send(spMetadata);
     }
   );
 
-router.post('/saml/SSO', passport.authenticate('saml', { failureRedirect: config.entryPoint+'/login', failureFlash: true}), function(req, res){
+router.post('/saml/SSO', passport.authenticate('saml', { failureRedirect: config.endpoint + "/login", failureFlash: true}), function(req, res){
     const xmlResponse = req.body.SAMLResponse;
     const parser = new Saml2js(xmlResponse);
     const response = parser.toObject();
@@ -140,7 +144,7 @@ router.post('/saml/SSO', passport.authenticate('saml', { failureRedirect: config
                                     ip: req.ip,
                                     device: "web",
                                     created_at: new Date(),
-                                    url : config.entryPoint
+                                    url : config.endpoint + "/"
                                   };
 
                                   db.Session.create(session)
@@ -152,7 +156,7 @@ router.post('/saml/SSO', passport.authenticate('saml', { failureRedirect: config
                                       var domain = (process.env.NODE_ENV == "production") ? new URL(config.get("endpoint")).hostname : req.headers.hostname;
                                       console.log("session set successfully");
                                       res.cookie('sdsession', token, { domain: domain, httpOnly: true });
-                                      res.redirect(302, config.entryPoint)
+                                      res.redirect(302, config.endpoint + "/")
                                     });
                         });
                 });
@@ -300,9 +304,9 @@ router.get('/saml/SLO', (req, res, next) => {
 
 router.get('/t/:id', (req, res) => {
   res.cookie('spacedeck_locale', req.params.id, { maxAge: 900000, httpOnly: true });
-  var path = "/";
+  var path = config.endpoint + "/";
   if (req.query.r=="login" || req.query.r=="signup") {
-    path = "/"+req.query.r;
+    path = config.endpoint + "/"+req.query.r;
   }
   res.redirect(path);
 });
@@ -316,7 +320,7 @@ router.get('/s/:hash', (req, res) => {
   db.Space.findOne({where: {"edit_hash": hash}}).then(function (space) {
     if (space) {
       if (req.accepts('text/html')){
-	      res.redirect("/spaces/"+space._id + "?spaceAuth=" + hash);
+	      res.redirect(config.endpoint + "/spaces/"+space._id + "?spaceAuth=" + hash);
       } else {
 	      res.status(200).json(space);
       }
diff --git a/spacedeck.js b/spacedeck.js
index 39ae665..d49ea10 100644
--- a/spacedeck.js
+++ b/spacedeck.js
@@ -76,7 +76,7 @@ const endpoint = config.get('endpoint');
 //app.use(require("./middlewares/cors"));
 app.use(require("./middlewares/session"));
 app.use(require("./middlewares/i18n"));
-app.use(endpoint+"/api", require("./middlewares/api_helpers"));
+app.use("/api", require("./middlewares/api_helpers"));
 app.use('/api/spaces/:id', require("./middlewares/space_helpers"));
 app.use('/api/spaces/:id/artifacts/:artifact_id', require("./middlewares/artifact_helpers"));
 
diff --git a/styles/icon.scss b/styles/icon.scss
index f95799b..8ceb3ef 100644
--- a/styles/icon.scss
+++ b/styles/icon.scss
@@ -92,5 +92,5 @@
 }
 
 .icon-sd6 {
-    background-image: url(/images/sd6-icon-white.svg);
+    background-image: url("<%= config.endpoint %>/images/sd6-icon-white.svg");
 }
diff --git a/views/partials/folders.html b/views/partials/folders.html
index f98576d..d2711d1 100644
--- a/views/partials/folders.html
+++ b/views/partials/folders.html
@@ -1,6 +1,6 @@
 <header id="folder-header" class="header" v-if="(active_view == 'folders' && active_folder)" v-cloak>
   <div v-cloak class="header-left pull-left">
-    <a class="btn btn-dark btn-md btn-round btn-icon" href="/spaces">
+    <a class="btn btn-dark btn-md btn-round btn-icon" href="<%= config.endpoint %>/spaces">
       <span class="icon icon-svg icon-sd6"></span>
     </a>
     <button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-dark btn-md btn-round" v-on:click="create_space('space')"><%= __('create_space') %></button>
@@ -58,21 +58,21 @@
       <div class="dropdown-menu" role="menu">
         <ul class="select-list">
           <li v-if="user.team && is_admin(user)">
-            <a href="/team">
+            <a href="<%= config.endpoint %>/team">
               <span class="icon icon-sm  icon-user-group"></span>
               <span><%=  __('edit_team') %></span>
             </a>
           </li>
 
           <li>
-            <a href="/account">
+            <a href="<%= config.endpoint %>/account">
               <span class="icon icon-sm  icon-user"></span>
               <span><%=  __('edit_account') %></span>
             </a>
           </li>
 
           <li>
-            <a href="/">
+            <a href="<%= config.endpoint %>/">
               <span class="icon icon-sm  icon-logout"></span>
               <span>Start</span>
             </a>
@@ -92,7 +92,7 @@
     <div id="folder-breadcrumb">
 
       <span v-if="logged_in" v-for="item in active_space_path" class="btn btn-sm btn-transparent" v-sd-droppable="handle_folder_drop;item">
-        <a href="/{{item.space_type}}s/{{item._id}}">{{item.name}}</a>&nbsp; â–¶</span>
+        <a href="<%= config.endpoint %>/{{item.space_type}}s/{{item._id}}">{{item.name}}</a>&nbsp; â–¶</span>
 
       <a v-if="(active_space_role != 'admin')" type="button" class="btn btn-sm btn-transparent">
         <span>{{active_folder.name}}</span>
@@ -143,7 +143,7 @@
           <span class="item-thumbnail" v-bind:style="space_thumbnail_style(item)"></span>
         </a>
         
-        <a v-if="active_space_role=='viewer' || logged_in" href="/{{item.space_type}}s/{{item._id}}">
+        <a v-if="active_space_role=='viewer' || logged_in" href="<%= config.endpoint %>/{{item.space_type}}s/{{item._id}}">
           <span class="item-thumbnail thumbnail-loading" v-if="item.space_type=='space'"></span>
           <span class="item-thumbnail" v-bind:style="space_thumbnail_style(item)"></span>
         </a>
diff --git a/views/partials/tool/toolbar-elements.html b/views/partials/tool/toolbar-elements.html
index 00154b9..bbdc3b7 100644
--- a/views/partials/tool/toolbar-elements.html
+++ b/views/partials/tool/toolbar-elements.html
@@ -3,14 +3,14 @@
   <div class="btn-group light vertical">
     
     <a class="btn btn-icon btn-transparent"
-       title="<%=__("home")%>" href="/spaces"
+       title="<%=__("home")%>" href="<%= config.endpoint %>/spaces"
        v-if="(!active_space.parent_space_id && !guest_nickname && !embedded)">
       <span class="icon icon-folder"></span>
     </a>
       
     <a class="btn btn-icon btn-dark"
        title="Parent Folder"
-       href="/folders/{{active_space.parent_space_id}}"
+       href="<%= config.endpoint %>/folders/{{active_space.parent_space_id}}"
        v-if="(active_space.parent_space_id && !guest_nickname && !embedded)">
       
       <span class="icon icon-sd6 icon-svg"></span>
diff --git a/views/spacedeck.ejs b/views/spacedeck.ejs
index ff285aa..3707263 100644
--- a/views/spacedeck.ejs
+++ b/views/spacedeck.ejs
@@ -19,9 +19,11 @@
       var ENV = {
         name: 'development',
         webHost: location.host,
-        webEndpoint: location.origin,
-        apiEndpoint: location.origin,
-        websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:")
+        webEndpoint: "<%= config.endpoint %>",
+        apiEndpoint: "<%= config.api_endpoint %>",
+        prefix: "<%= config.prefix %>",
+        //websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:")
+        websocketsEndpoint: "<%= config.endpoint %>".replace("https:","wss:").replace("http:","ws:")
       };
     </script>
 
-- 
GitLab