12033: Log out and back in to a site without forgetting it.
[arvados.git] / apps / workbench / app / assets / javascripts / models / session_db.js
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 window.models = window.models || {}
6 window.models.SessionDB = function() {
7     var db = this
8     Object.assign(db, {
9         loadFromLocalStorage: function() {
10             try {
11                 return JSON.parse(window.localStorage.getItem('sessions')) || {}
12             } catch(e) {}
13             return {}
14         },
15         loadAll: function() {
16             var all = db.loadFromLocalStorage()
17             if (window.defaultSession) {
18                 window.defaultSession.isFromRails = true
19                 all[window.defaultSession.user.uuid.slice(0, 5)] = window.defaultSession
20             }
21             return all
22         },
23         loadActive: function() {
24             var sessions = db.loadAll()
25             Object.keys(sessions).forEach(function(key) {
26                 if (!sessions[key].token)
27                     delete sessions[key]
28             })
29             return sessions
30         },
31         save: function(k, v) {
32             var sessions = db.loadAll()
33             sessions[k] = v
34             Object.keys(sessions).forEach(function(key) {
35                 if (sessions[key].isFromRails)
36                     delete sessions[key]
37             })
38             window.localStorage.setItem('sessions', JSON.stringify(sessions))
39         },
40         trash: function(k) {
41             var sessions = db.loadAll()
42             delete sessions[k]
43             window.localStorage.setItem('sessions', JSON.stringify(sessions))
44         },
45         login: function(host) {
46             // Initiate login procedure with given API host (which can
47             // optionally include scheme://).
48             //
49             // Any page that has a button that invokes login() must
50             // also call checkForNewToken() on (at least) its first
51             // render. Otherwise, the login procedure can't be
52             // completed.
53             var baseURL = host
54             if (baseURL.indexOf('://') < 0)
55                 baseURL = 'https://' + baseURL
56             if (!baseURL.endsWith('/'))
57                 baseURL = baseURL + '/'
58             document.location = baseURL + 'login?return_to=' + encodeURIComponent(document.location.href.replace(/\?.*/, '')+'?baseURL='+encodeURIComponent(baseURL))
59             return false
60         },
61         logout: function(k) {
62             // Forget the token, but leave the other info in the db so
63             // the user can log in again without providing the login
64             // host again.
65             var sessions = db.loadAll()
66             delete sessions[k].token
67             db.save(k, sessions[k])
68         },
69         checkForNewToken: function() {
70             // If there's a token and baseURL in the location bar (i.e.,
71             // we just landed here after a successful login), save it and
72             // scrub the location bar.
73             if (!document.location.search.startsWith('?'))
74                 return
75             var params = {}
76             document.location.search.slice(1).split('&').map(function(kv) {
77                 var e = kv.indexOf('=')
78                 if (e < 0)
79                     return
80                 params[decodeURIComponent(kv.slice(0, e))] = decodeURIComponent(kv.slice(e+1))
81             })
82             if (!params.baseURL || !params.api_token)
83                 // Have a query string, but it's not a login callback.
84                 return
85             params.token = params.api_token
86             delete params.api_token
87             db.save(params.baseURL, params)
88             history.replaceState({}, '', document.location.origin + document.location.pathname)
89         },
90         fillMissingUUIDs: function() {
91             var sessions = db.loadAll()
92             Object.keys(sessions).map(function(key) {
93                 if (key.indexOf('://') < 0)
94                     return
95                 // key is the baseURL placeholder. We need to get our user
96                 // record to find out the cluster's real uuid prefix.
97                 var session = sessions[key]
98                 m.request(session.baseURL+'arvados/v1/users/current', {
99                     headers: {
100                         authorization: 'OAuth2 '+session.token,
101                     },
102                 }).then(function(user) {
103                     session.user = user
104                     db.save(user.uuid.slice(0, 5), session)
105                     db.trash(key)
106                 })
107             })
108             // m.request(session.baseURL + 'discovery/v1/apis/arvados/v1/rest').then(function(dd) {})
109         },
110         request: function(session, path, opts) {
111             opts = opts || {}
112             opts.headers = opts.headers || {}
113             opts.headers.authorization = 'OAuth2 '+ session.token
114             return m.request(session.baseURL + path, opts)
115         },
116     })
117 }