Skip to content

Commit 0b45d67

Browse files
committed
FIX: Auth session should be persisted after refresh (fixes #163).
1 parent d092e5f commit 0b45d67

File tree

9 files changed

+51
-36
lines changed

9 files changed

+51
-36
lines changed

frontend/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"type": "module",
66
"dependencies": {
77
"bootstrap": "^5.2.2",
8-
"buffer": "^6.0.3",
98
"events": "^3.3.0",
109
"react": "^18.2.0",
1110
"react-bootstrap": "^2.5.0",

frontend/src/App.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ function App() {
2525
setTypes(rows);
2626
}
2727
);
28+
backend.getSession()
29+
.then(setUser);
2830
}, []);
2931
return (
3032
<StrictMode>

frontend/src/components/Bookmark.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid';
44

55
function Bookmark({backend, id}) {
66
const [isBookmarked, setIsBookmarked] = useState(false);
7-
let user = backend.credentials.name;
7+
let user = backend.user;
88

99
const getBookmark = useCallback((id, user) =>
1010
backend.getView({view: 'bookmark', id: user, options: ['include_docs']})

frontend/src/components/FutureDocument.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function FutureDocumentIcon({relatedTo, verb, setLastUpdate, backend}) {
5757
let _id = uuid().replace(/-/g, '');
5858
let doc = {
5959
_id,
60-
editors: [backend.credentials.name],
60+
editors: [backend.user],
6161
dc_creator: '<CREATOR>',
6262
dc_title: '<TITLE>',
6363
dc_issued: new Date(),

frontend/src/components/Menu.jsx

+7-4
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@ function Authentication({backend, user, setUser}) {
3333
let handleSubmit = (e) => {
3434
e.preventDefault();
3535
let credentials = Object.fromEntries(new FormData(e.target).entries());
36-
backend.authenticate(credentials)
37-
.then(() => setUser(credentials.name))
38-
.catch(console.error);
36+
backend.postSession(credentials)
37+
.then((x) => {
38+
if (x) {
39+
setUser(x);
40+
}
41+
});
3942
};
4043

4144
if (user) return (
@@ -44,7 +47,7 @@ function Authentication({backend, user, setUser}) {
4447
{user}
4548
</Dropdown.Toggle>
4649
<Dropdown.Menu>
47-
<SignOutAction/>
50+
<SignOutAction {...{setUser, backend}} />
4851
</Dropdown.Menu>
4952
</Dropdown>
5053
);

frontend/src/components/SignOutAction.jsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import Dropdown from 'react-bootstrap/Dropdown';
22

3-
function SignOutAction() {
3+
function SignOutAction({setUser, backend}) {
4+
5+
const handleSignOut = () => {
6+
backend.deleteSession();
7+
setUser();
8+
};
9+
410
return (
5-
<Dropdown.Item onClick={() => window.location.reload()}>
11+
<Dropdown.Item onClick={handleSignOut}>
612
Sign out
713
</Dropdown.Item>
814
);

frontend/src/hyperglosae.js

+26-27
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import {Buffer} from 'buffer';
2-
31
const service = '/api';
42

53
function Hyperglosae(logger) {
64

7-
this.credentials = {};
8-
95
this.getView = ({view, id, options = []}) =>
106
fetch(`${
117
service
@@ -23,18 +19,9 @@ function Hyperglosae(logger) {
2319
fetch(`${service}/${id}`)
2420
.then(x => x.json());
2521

26-
let basicAuthentication = ({force}) => {
27-
let {name, password} = this.credentials;
28-
if (!force && !name && !password) return ({});
29-
return ({
30-
'Authorization': 'Basic ' + Buffer.from(`${name}:${password}`).toString('base64')
31-
});
32-
};
33-
3422
this.putDocument = (doc, uri) =>
3523
fetch(`${service}/${uri || doc._id}`, {
3624
method: 'PUT',
37-
headers: basicAuthentication({force: false}),
3825
body: JSON.stringify(doc)
3926
})
4027
.then(x => x.json())
@@ -49,7 +36,6 @@ function Hyperglosae(logger) {
4936
this.deleteDocument = ({_id, _rev}) =>
5037
fetch(`${service}/${_id}?rev=${_rev}`, {
5138
method: 'DELETE',
52-
headers: basicAuthentication({ force: false })
5339
})
5440
.then(x => x.json())
5541
.then(x => {
@@ -63,7 +49,6 @@ function Hyperglosae(logger) {
6349
this.getDocumentMetadata = (id) =>
6450
fetch(`${service}/${id}`, {
6551
method: 'HEAD',
66-
headers: basicAuthentication({ force: false })
6752
});
6853

6954
this.putAttachment = (id, attachment, callback) =>
@@ -76,7 +61,6 @@ function Hyperglosae(logger) {
7661
fetch(`${service}/${id}/${attachment.name}`, {
7762
method: 'PUT',
7863
headers: {
79-
...basicAuthentication({ force: false }),
8064
// ETag is the header that carries the current rev.
8165
'If-Match': x.headers.get('ETag'),
8266
'Content-Type': attachment.type
@@ -86,19 +70,34 @@ function Hyperglosae(logger) {
8670
};
8771
});
8872

89-
this.authenticate = ({name, password}) => {
90-
this.credentials = {name, password};
91-
return fetch(`${service}`, {
92-
method: 'GET',
93-
headers: basicAuthentication({force: true})
73+
this.getSession = () =>
74+
fetch(`${service}/_session`)
75+
.then(x => x.json())
76+
.then(x => {
77+
this.user = x.userCtx?.name;
78+
return this.user;
79+
});
80+
81+
this.postSession = ({name, password}) =>
82+
fetch(`${service}/_session`, {
83+
method: 'POST',
84+
headers: {
85+
'Content-Type': 'application/x-www-form-urlencoded',
86+
},
87+
body: `name=${name}&password=${password}`
9488
})
9589
.then(x => x.json())
9690
.then(x => {
97-
if (x.reason) {
98-
this.credentials = {};
99-
logger(x.reason);
100-
throw new Error(x.reason);
101-
}
91+
if (!x.reason) return this.user = name;
92+
logger(x.reason);
93+
});
94+
95+
this.deleteSession = () => {
96+
fetch(`${service}/_session`, {
97+
method: 'DELETE'
98+
})
99+
.then(() => {
100+
this.user = null;
102101
});
103102
};
104103

@@ -125,7 +124,7 @@ function Hyperglosae(logger) {
125124
};
126125

127126
this.refreshDocuments = (callback) => {
128-
let id = this.credentials.name || 'PUBLIC';
127+
let id = this.user || 'PUBLIC';
129128
this.getView({view: 'all_documents', id, options: ['include_docs']})
130129
.then((rows) => {
131130
callback(

frontend/vite.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export default defineConfig({
1616
changeOrigin: true,
1717
rewrite: (path) => path.replace(/^\/api\/_users/, ''),
1818
},
19+
'/api/_session': {
20+
target: 'http://localhost:5984/_session',
21+
changeOrigin: true,
22+
rewrite: (path) => path.replace(/^\/api\/_session/, ''),
23+
},
1924
'/api': {
2025
target: 'http://localhost:5984/hyperglosae',
2126
changeOrigin: true,

settings/haproxy.cfg

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ frontend http-in
3030
backend couchdb
3131
option httpchk GET /_up
3232
http-check disable-on-404
33+
http-request replace-path /api/_session /_session
3334
http-request replace-path /api/_users/(.*) /_users/\1
3435
http-request replace-path /api(/)?(.*) /hyperglosae/\2
3536
server couchdb1 backend:5984 check inter 5s

0 commit comments

Comments
 (0)