blob: c256d511642de7fc1644d3bdf171c811c7ceda49 [file] [log] [blame]
Adrien Béraud6ecaa402021-04-06 17:37:25 -04001/*
2 * Copyright (c) 2017-2021 Savoir-faire Linux Inc.
3 *
4 * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
Adrien Béraud6ecaa402021-04-06 17:37:25 -040020class AuthManager {
21 constructor() {
22 console.log("AuthManager()")
Adrien Béraud6ecaa402021-04-06 17:37:25 -040023 this.authenticating = false
Adrien Béraude74741b2021-04-19 13:22:54 -040024
25 this.state = {
26 initialized: false,
27 authenticated: true,
28 setupComplete: true,
29 error: false
30 }
31
Adrien Béraud6ecaa402021-04-06 17:37:25 -040032 this.tasks = []
33 this.onAuthChanged = undefined
34 }
Adrien Béraud6ecaa402021-04-06 17:37:25 -040035
36 isAuthenticated() {
Adrien Béraude74741b2021-04-19 13:22:54 -040037 return this.state.authenticated
Adrien Béraud6ecaa402021-04-06 17:37:25 -040038 }
39
Adrien Béraude74741b2021-04-19 13:22:54 -040040 getState() {
41 return this.state
42 }
43
44 init(cb) {
45 this.onAuthChanged = cb
46 if (this.state.initialized || this.authenticating)
47 return
48 console.log("Init")
49 this.authenticating = true
50 fetch('/auth')
51 .then(async (response) => {
52 this.authenticating = false
53 this.state.initialized = true
54 console.log("Init ended")
Adrien Béraude74741b2021-04-19 13:22:54 -040055 if (response.status === 200) {
56 const jsonData = await response.json()
57 Object.assign(this.state, {
58 authenticated: true,
59 setupComplete: true,
60 error: false,
61 user: { username: jsonData.username, type: jsonData.type }
62 })
63 } else if (response.status === 401) {
64 const jsonData = await response.json()
65 Object.assign(this.state, {
66 authenticated: false,
67 setupComplete: 'setupComplete' in jsonData ? jsonData.setupComplete : true,
68 error: false
69 })
70 } else {
71 this.state.error = true
72 }
Adrien Béraude74741b2021-04-19 13:22:54 -040073 if (this.onAuthChanged)
74 this.onAuthChanged(this.state)
75 })
76 }
77
78 deinit() {
79 console.log("Deinit")
80 this.onAuthChanged = undefined
81 }
82
83 async setup(password) {
84 if (this.authenticating || this.state.setupComplete)
85 return
86 console.log("Starting setup")
87 this.authenticating = true
88 const response = await fetch(`/setup`, {
89 method: 'POST',
90 headers: {
91 'Accept': 'application/json',
92 'Content-Type': 'application/json'
93 },
94 body: JSON.stringify({ password })
95 })
96 console.log(response)
97 if (response.ok) {
98 console.log("Success, going home")
99 //history.replace('/')
100 } else {
101 }
102 this.authenticating = false
103 this.state.setupComplete = true
104 if (this.onAuthChanged)
105 this.onAuthChanged(this.state)
106 return response.ok
107 }
108
109 authenticate(username, password) {
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400110 if (this.authenticating)
111 return
112 console.log("Starting authentication")
113 this.authenticating = true
Adrien Béraude74741b2021-04-19 13:22:54 -0400114 fetch(`/auth/local?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`, { method:"POST" })
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400115 .then(response => {
116 console.log(response)
117 this.authenticating = false
Adrien Béraude74741b2021-04-19 13:22:54 -0400118 this.state.authenticated = response.ok && response.status === 200
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400119 if (this.onAuthChanged)
Adrien Béraude74741b2021-04-19 13:22:54 -0400120 this.onAuthChanged(this.state)
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400121 while (this.tasks.length !== 0) {
122 const task = this.tasks.shift()
Adrien Béraude74741b2021-04-19 13:22:54 -0400123 if (this.state.authenticated)
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400124 fetch(task.url, task.init).then(res => task.resolve(res))
125 else
126 task.reject(new Error("Authentication failed"))
127 }
128 })
129 }
130
131 disconnect() {
132 console.log("Disconnect")
Adrien Béraude74741b2021-04-19 13:22:54 -0400133 this.state.authenticated = false
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400134 if (this.onAuthChanged)
Adrien Béraude74741b2021-04-19 13:22:54 -0400135 this.onAuthChanged(this.state)
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400136 }
137
138 fetch(url, init) {
Adrien Béraud150b4782021-04-21 19:40:59 -0400139 console.log(`fetch ${url}`)
Adrien Béraude74741b2021-04-19 13:22:54 -0400140 if (!this.state.authenticated) {
Adrien Béraud4e287b92021-04-24 16:15:56 -0400141 if (!init || !init.method || init.method === 'GET') {
142 return new Promise((resolve, reject) => this.tasks.push({url, init, resolve, reject}))
143 } else {
144 return new Promise((resolve, reject) => reject("Not authenticated"))
145 }
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400146 }
147 return fetch(url, init)
148 .then(response => {
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400149 if (response.status === 401) {
150 this.disconnect()
151 return this.fetch(url, init)
152 }
153 return response
154 })
155 }
156}
157
158export default new AuthManager()