@cloudron/tegel 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +57 -27
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -6,8 +6,12 @@ import FileStoreFactory from 'session-file-store';
|
|
|
6
6
|
import { lastMile, HttpError } from '@cloudron/connect-lastmile';
|
|
7
7
|
import * as oidc from './src/oidc.js';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
let _testMode = null;
|
|
10
|
+
|
|
11
|
+
export async function createExpressApp({ oidcConfig, testMode, jsonBodySizeLimit = '25mb', skipLastMile = false }) {
|
|
12
|
+
_testMode = testMode || null;
|
|
13
|
+
|
|
14
|
+
if (!_testMode && oidcConfig) await oidc.initOIDC(oidcConfig);
|
|
11
15
|
|
|
12
16
|
const app = express();
|
|
13
17
|
|
|
@@ -17,32 +21,41 @@ export async function createExpressApp({ oidcConfig, jsonBodySizeLimit = '25mb',
|
|
|
17
21
|
|
|
18
22
|
app.use(express.json({ limit: jsonBodySizeLimit }));
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
fs.writeFileSync(sessionSecretFile, sessionSecret, { mode: 0o600 });
|
|
24
|
+
if (_testMode) {
|
|
25
|
+
app.use(session({
|
|
26
|
+
secret: 'test-secret',
|
|
27
|
+
resave: false,
|
|
28
|
+
saveUninitialized: false,
|
|
29
|
+
cookie: { secure: false }
|
|
30
|
+
}));
|
|
28
31
|
} else {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
cookie: {
|
|
40
|
-
secure: process.env.NODE_ENV === 'production',
|
|
41
|
-
httpOnly: true,
|
|
42
|
-
sameSite: 'lax',
|
|
43
|
-
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
|
32
|
+
const FileStore = FileStoreFactory(session);
|
|
33
|
+
const sessionStorePath = process.env.CLOUDRON ? '/app/data/.session.store' : '/tmp/session.store';
|
|
34
|
+
const sessionSecretFile = process.env.CLOUDRON ? '/app/data/.session.secret' : '/tmp/.session.secret';
|
|
35
|
+
|
|
36
|
+
let sessionSecret;
|
|
37
|
+
if (!fs.existsSync(sessionSecretFile)) {
|
|
38
|
+
sessionSecret = crypto.randomBytes(64).toString('hex');
|
|
39
|
+
fs.writeFileSync(sessionSecretFile, sessionSecret, { mode: 0o600 });
|
|
40
|
+
} else {
|
|
41
|
+
sessionSecret = fs.readFileSync(sessionSecretFile, 'utf8').trim();
|
|
44
42
|
}
|
|
45
|
-
|
|
43
|
+
|
|
44
|
+
fs.mkdirSync(sessionStorePath, { recursive: true });
|
|
45
|
+
|
|
46
|
+
app.use(session({
|
|
47
|
+
secret: sessionSecret,
|
|
48
|
+
store: new FileStore({ path: sessionStorePath }),
|
|
49
|
+
resave: false,
|
|
50
|
+
saveUninitialized: false,
|
|
51
|
+
cookie: {
|
|
52
|
+
secure: process.env.NODE_ENV === 'production',
|
|
53
|
+
httpOnly: true,
|
|
54
|
+
sameSite: 'lax',
|
|
55
|
+
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
|
56
|
+
}
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
46
59
|
|
|
47
60
|
const router = new express.Router();
|
|
48
61
|
router.del = router.delete; // amend router.del for readability further on
|
|
@@ -58,6 +71,8 @@ export async function createExpressApp({ oidcConfig, jsonBodySizeLimit = '25mb',
|
|
|
58
71
|
export const servePath = express.static;
|
|
59
72
|
|
|
60
73
|
export async function oidcRedirectToLoginProvider(req, res, next) {
|
|
74
|
+
if (_testMode) return res.redirect('/');
|
|
75
|
+
|
|
61
76
|
try {
|
|
62
77
|
// Store the frontend origin for redirecting after login
|
|
63
78
|
// This allows Vite dev server (port 5173) to work with OIDC callback (port 3000)
|
|
@@ -78,7 +93,7 @@ export async function oidcRedirectToLoginProvider(req, res, next) {
|
|
|
78
93
|
} catch (error) {
|
|
79
94
|
console.error('Login error:', error);
|
|
80
95
|
|
|
81
|
-
next(new HttpError(500, 'Failed to initiate oidc flow.'))
|
|
96
|
+
next(new HttpError(500, 'Failed to initiate oidc flow.'));
|
|
82
97
|
}
|
|
83
98
|
}
|
|
84
99
|
|
|
@@ -88,6 +103,8 @@ export function oidcCallback(successRedirectTo, errorRedirectTo, successHook = a
|
|
|
88
103
|
if (!successHook || typeof successHook !== 'function') throw new Error('oidcCallback needs a successHook path as a function');
|
|
89
104
|
|
|
90
105
|
return async (req, res) => {
|
|
106
|
+
if (_testMode) return res.redirect(successRedirectTo);
|
|
107
|
+
|
|
91
108
|
// Redirect to the frontend origin that initiated the login (supports Vite dev server)
|
|
92
109
|
const frontendOrigin = req.session.frontendOrigin;
|
|
93
110
|
delete req.session.frontendOrigin; // Clean up
|
|
@@ -113,6 +130,8 @@ export function logout(redirectTo) {
|
|
|
113
130
|
if (!redirectTo || typeof redirectTo !== 'string') throw new Error('logout needs a redirectTo path as non-empty string');
|
|
114
131
|
|
|
115
132
|
return (req, res) => {
|
|
133
|
+
if (_testMode) return res.redirect(redirectTo);
|
|
134
|
+
|
|
116
135
|
let redirectUri = '';
|
|
117
136
|
|
|
118
137
|
// Get the referer to redirect back to the same origin (supports Vite dev server)
|
|
@@ -130,6 +149,12 @@ export function logout(redirectTo) {
|
|
|
130
149
|
|
|
131
150
|
req.session.destroy((error) => {
|
|
132
151
|
if (error) console.error('Logout error:', error);
|
|
152
|
+
res.clearCookie('connect.sid', {
|
|
153
|
+
path: '/',
|
|
154
|
+
httpOnly: true,
|
|
155
|
+
secure: process.env.NODE_ENV === 'production',
|
|
156
|
+
sameSite: 'lax'
|
|
157
|
+
});
|
|
133
158
|
res.redirect(redirectUri + redirectTo);
|
|
134
159
|
});
|
|
135
160
|
};
|
|
@@ -139,6 +164,11 @@ export function requireAuth(redirectTo = '', { requiredScopes = [] } = {}) {
|
|
|
139
164
|
if (typeof redirectTo !== 'string') throw new Error('requireAuth needs a redirectTo path as non-empty string');
|
|
140
165
|
|
|
141
166
|
return async (req, res, next) => {
|
|
167
|
+
if (_testMode) {
|
|
168
|
+
req.user = { ..._testMode };
|
|
169
|
+
return next();
|
|
170
|
+
}
|
|
171
|
+
|
|
142
172
|
const accessToken = extractAccessToken(req);
|
|
143
173
|
|
|
144
174
|
if (accessToken) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudron/tegel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "GPL-2.0",
|
|
6
6
|
"author": "Cloudron Developers",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@eslint/js": "^10.0.1",
|
|
23
|
-
"eslint": "^10.0.
|
|
23
|
+
"eslint": "^10.0.3",
|
|
24
24
|
"globals": "^17.4.0"
|
|
25
25
|
}
|
|
26
26
|
}
|