blob: 60c903bfed3329476699ed9ad75a8032c45c1d5e [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 {
simond47ef9e2022-09-28 22:24:28 -040021 constructor() {
22 console.log('AuthManager()');
23 this.authenticating = false;
Adrien Béraude74741b2021-04-19 13:22:54 -040024
simond47ef9e2022-09-28 22:24:28 -040025 this.state = {
26 initialized: false,
27 authenticated: true,
28 setupComplete: true,
29 error: false,
30 };
Adrien Béraude74741b2021-04-19 13:22:54 -040031
simond47ef9e2022-09-28 22:24:28 -040032 this.tasks = [];
33 this.onAuthChanged = undefined;
Adrien Béraude5cad982021-06-07 10:05:50 -040034
simond47ef9e2022-09-28 22:24:28 -040035 if (initData) {
36 console.log('Using static initData');
37 this.setInitData(initData);
38 return;
Adrien Béraud6ecaa402021-04-06 17:37:25 -040039 }
simond47ef9e2022-09-28 22:24:28 -040040 }
Adrien Béraud6ecaa402021-04-06 17:37:25 -040041
simond47ef9e2022-09-28 22:24:28 -040042 isAuthenticated() {
43 return this.state.authenticated;
44 }
45
46 getState() {
47 return this.state;
48 }
49
50 setInitData(data) {
51 this.authenticating = false;
52 this.state.initialized = true;
53 if (data.username) {
54 Object.assign(this.state, {
55 authenticated: true,
56 setupComplete: true,
57 error: false,
58 user: { username: data.username, type: data.type },
59 });
60 } else {
61 Object.assign(this.state, {
62 authenticated: false,
63 setupComplete: 'setupComplete' in data ? data.setupComplete : true,
64 error: false,
65 });
Adrien Béraud6ecaa402021-04-06 17:37:25 -040066 }
simond47ef9e2022-09-28 22:24:28 -040067 console.log('Init ended');
68 /*if (this.onAuthChanged)
Adrien Béraude5cad982021-06-07 10:05:50 -040069 this.onAuthChanged(this.state)*/
simond47ef9e2022-09-28 22:24:28 -040070 }
Adrien Béraude5cad982021-06-07 10:05:50 -040071
simond47ef9e2022-09-28 22:24:28 -040072 init(cb) {
73 this.onAuthChanged = cb;
74 if (this.state.initialized || this.authenticating) return;
75 /*if (initData) {
Adrien Béraude5cad982021-06-07 10:05:50 -040076 console.log("Using static initData")
77 this.setInitData(initData)
78 return
79 }*/
simond47ef9e2022-09-28 22:24:28 -040080 this.authenticating = true;
81 fetch('/auth')
82 .then(async (response) => {
83 this.authenticating = false;
84 this.state.initialized = true;
85 if (response.status === 200) {
86 this.setInitData(await response.json());
87 } else if (response.status === 401) {
88 this.setInitData(await response.json());
Adrien Béraude74741b2021-04-19 13:22:54 -040089 } else {
simond47ef9e2022-09-28 22:24:28 -040090 this.state.error = true;
91 if (this.onAuthChanged) this.onAuthChanged(this.state);
Adrien Béraude74741b2021-04-19 13:22:54 -040092 }
simond47ef9e2022-09-28 22:24:28 -040093 })
94 .catch((e) => {
95 this.authenticating = false;
96 console.log(e);
97 });
98 }
Adrien Béraude74741b2021-04-19 13:22:54 -040099
simond47ef9e2022-09-28 22:24:28 -0400100 deinit() {
101 console.log('Deinit');
102 this.onAuthChanged = undefined;
103 }
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400104
simond47ef9e2022-09-28 22:24:28 -0400105 async setup(password) {
106 if (this.authenticating || this.state.setupComplete) return;
107 console.log('Starting setup');
108 this.authenticating = true;
109 const response = await fetch(`/setup`, {
110 method: 'POST',
111 headers: {
112 Accept: 'application/json',
113 'Content-Type': 'application/json',
114 },
115 body: JSON.stringify({ password }),
116 });
117 console.log(response);
118 if (response.ok) {
119 console.log('Success, going home');
120 //navigate('/')
121 } else {
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400122 }
simond47ef9e2022-09-28 22:24:28 -0400123 this.authenticating = false;
124 this.state.setupComplete = true;
125 if (this.onAuthChanged) this.onAuthChanged(this.state);
126 return response.ok;
127 }
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400128
simond47ef9e2022-09-28 22:24:28 -0400129 authenticate(username, password) {
130 if (this.authenticating) return;
131 console.log('Starting authentication');
132 this.authenticating = true;
133 fetch(`/auth/local?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`, {
134 method: 'POST',
135 })
136 .then((response) => {
137 console.log(response);
138 this.authenticating = false;
139 this.state.authenticated = response.ok && response.status === 200;
140 if (this.onAuthChanged) this.onAuthChanged(this.state);
141 while (this.tasks.length !== 0) {
142 const task = this.tasks.shift();
143 if (this.state.authenticated)
144 fetch(task.url, task.init)
145 .then((res) => task.resolve(res))
146 .catch((e) => console.log('Error executing pending task: ' + e));
147 else task.reject(new Error('Authentication failed'));
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400148 }
simond47ef9e2022-09-28 22:24:28 -0400149 })
150 .catch((e) => {
151 this.authenticating = false;
152 console.log(e);
153 });
154 }
155
156 disconnect() {
157 console.log('Disconnect');
158 this.state.authenticated = false;
159 if (this.onAuthChanged) this.onAuthChanged(this.state);
160 }
161
162 fetch(url, init) {
163 console.log(`fetch ${url}`);
164 if (!this.state.authenticated) {
165 if (!init || !init.method || init.method === 'GET') {
166 return new Promise((resolve, reject) => this.tasks.push({ url, init, resolve, reject }));
167 } else {
168 return new Promise((resolve, reject) => reject('Not authenticated'));
169 }
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400170 }
simond47ef9e2022-09-28 22:24:28 -0400171 return fetch(url, init).then((response) => {
172 if (response.status === 401) {
173 this.disconnect();
174 return this.fetch(url, init);
175 }
176 return response;
177 });
178 }
Adrien Béraud6ecaa402021-04-06 17:37:25 -0400179}
180
simond47ef9e2022-09-28 22:24:28 -0400181export default new AuthManager();