Improve error messages (#77)

This commit is contained in:
Gabriel Massadas
2025-01-04 12:59:00 +00:00
committed by GitHub
parent 1639e4368f
commit a74fde5af6
10 changed files with 74 additions and 102 deletions
+10 -3
View File
@@ -2,14 +2,21 @@ import { boot } from "quasar/wrappers";
import { useAuthStore } from "stores/auth-store";
import { useMainStore } from "stores/main-store";
export default boot(async ({ router, store }) => {
export default boot(async ({ app, router, store }) => {
// Check if theres any auth token stored, if there is, try to fetch or redirect
const authStore = useAuthStore(store);
const authResp = await authStore.CheckLoginInStorage(router);
const authResp = await authStore.CheckLoginInStorage(
router,
app.config.globalProperties.$q,
);
if (authResp === false) {
// No auth token stored, try to fetch without auth or redirect
const mainStore = useMainStore(store);
await mainStore.loadServerConfigs(router, true);
await mainStore.loadServerConfigs(
router,
app.config.globalProperties.$q,
true,
);
}
});
@@ -28,23 +28,11 @@
import LeftSidebar from "components/main/LeftSidebar.vue";
import RightSidebar from "components/main/RightSidebar.vue";
import TopBar from "components/main/Topbar.vue";
import { useMainStore } from "stores/main-store";
import { ref } from "vue";
export default {
name: "MainLayout",
components: { TopBar, RightSidebar, LeftSidebar },
created() {
const mainStore = useMainStore();
mainStore.loadUserDisks().then((buckets) => {
if (this.$route.path === "/") {
this.$router.push({
name: "files-home",
params: { bucket: buckets[0].name },
});
}
});
},
setup() {
const leftDrawerOpen = ref(false);
const rightDrawerOpen = ref(false);
+8 -24
View File
@@ -5,10 +5,7 @@ import { useMainStore } from "stores/main-store";
const SESSION_KEY = "r2_explorer_session_token";
export const useAuthStore = defineStore("auth", {
state: () => ({
user: "",
loginMethod: "",
}),
state: () => ({}),
getters: {
isAuthenticated: (state) => !!state.user,
StateUser: (state) => state.user,
@@ -20,7 +17,7 @@ export const useAuthStore = defineStore("auth", {
api.defaults.headers.common["Authorization"] = `Basic ${token}`;
try {
await mainStore.loadServerConfigs(router);
await mainStore.loadServerConfigs(router, this.q);
} catch (e) {
console.log(e);
delete api.defaults.headers.common["Authorization"];
@@ -29,19 +26,15 @@ export const useAuthStore = defineStore("auth", {
api.defaults.headers.common.Authorization = `Basic ${token}`;
this.loginMethod = "basic";
this.user = form.email;
if (form.remind === true) {
localStorage.setItem(SESSION_KEY, token);
} else {
sessionStorage.setItem(SESSION_KEY, token);
}
router.replace(router.currentRoute.value.query?.next || "/");
},
async CheckLoginInStorage(router) {
async CheckLoginInStorage(router, q) {
let token = sessionStorage.getItem(SESSION_KEY);
let authed = false;
if (!token) {
token = localStorage.getItem(SESSION_KEY);
}
@@ -53,27 +46,18 @@ export const useAuthStore = defineStore("auth", {
const mainStore = useMainStore();
api.defaults.headers.common["Authorization"] = `Basic ${token}`;
try {
await mainStore.loadServerConfigs(router);
} catch (e) {
// Auth token expired
authed = await mainStore.loadServerConfigs(router, q, true);
if (!authed) {
delete api.defaults.headers.common["Authorization"];
await router.replace({
name: "login",
query: { next: router.currentRoute.fullPath },
});
return;
return false;
}
this.user = atob(token).split(":")[0];
this.loginMethod = "basic";
return false;
},
async LogOut(router) {
localStorage.removeItem(SESSION_KEY);
sessionStorage.removeItem(SESSION_KEY);
this.user = "";
this.loginMethod = "";
await router.replace({ name: "login" });
},
},
+24 -8
View File
@@ -22,13 +22,7 @@ export const useMainStore = defineStore("main", {
},
},
actions: {
async loadUserDisks() {
const response = await api.get("/buckets");
this.buckets = response.data.buckets;
return response.data.buckets;
},
async loadServerConfigs(router, handleError = false) {
async loadServerConfigs(router, q, handleError = false) {
// This is the initial requests to server, that also checks if user needs auth
try {
@@ -41,6 +35,19 @@ export const useMainStore = defineStore("main", {
this.auth = response.data.auth;
this.version = response.data.version;
this.showHiddenFiles = response.data.config.showHiddenFiles;
this.buckets = response.data.buckets;
const url = new URL(window.location.href);
if (url.searchParams.get("next")) {
await router.replace(url.searchParams.get("next"));
} else if (url.pathname === "/" || url.pathname === "/auth/login") {
await router.push({
name: "files-home",
params: { bucket: this.buckets[0].name },
});
}
return true;
} catch (error) {
console.log(error);
if (error.response.status === 302) {
@@ -52,17 +59,26 @@ export const useMainStore = defineStore("main", {
}
if (handleError) {
if (error.response?.status === 401) {
const respText = await error.response.data;
if (respText === "Authentication error: Basic Auth required") {
await router.push({
name: "login",
query: { next: router.currentRoute.value.fullPath },
});
return;
}
q.notify({
type: "negative",
message: respText,
timeout: 10000, // we will timeout it in 10s
});
} else {
throw error;
}
}
return false;
},
},
});
+1 -1
View File
@@ -61,7 +61,7 @@
"dependencies": {
"@hono/cloudflare-access": "^0.2.0",
"chanfana": "^2.5.1",
"hono": "^4.6.14",
"hono": "^4.6.15",
"postal-mime": "^2.3.2",
"zod": "^3.24.1"
}
+8 -16
View File
@@ -14,7 +14,6 @@ import { CreateFolder } from "./modules/buckets/createFolder";
import { DeleteObject } from "./modules/buckets/deleteObject";
import { GetObject } from "./modules/buckets/getObject";
import { HeadObject } from "./modules/buckets/headObject";
import { ListBuckets } from "./modules/buckets/listBuckets";
import { ListObjects } from "./modules/buckets/listObjects";
import { MoveObject } from "./modules/buckets/moveObject";
import { CompleteUpload } from "./modules/buckets/multipart/completeUpload";
@@ -30,7 +29,7 @@ import type {
AppContext,
AppEnv,
AppVariables,
BasicAuth,
BasicAuthType,
R2ExplorerConfig,
} from "./types";
@@ -68,23 +67,16 @@ export function R2Explorer(config?: R2ExplorerConfig) {
});
if (config.cors === true) {
app.use(
"*",
cors({
origin: "*",
allowMethods: ["*"],
credentials: true,
}),
);
app.use("/api/*", cors());
}
if (config.readonly === true) {
app.use("*", readOnlyMiddleware);
app.use("/api/*", readOnlyMiddleware);
}
if (config.cfAccessTeamName) {
app.use("*", cloudflareAccess(config.cfAccessTeamName));
app.use("*", async (c, next) => {
app.use("/api/*", cloudflareAccess(config.cfAccessTeamName));
app.use("/api/*", async (c, next) => {
c.set("authentication_type", "cloudflare-access");
c.set("authentication_username", c.get("accessPayload").email);
await next();
@@ -97,14 +89,15 @@ export function R2Explorer(config?: R2ExplorerConfig) {
scheme: "basic",
});
app.use(
"*",
"/api/*",
basicAuth({
invalidUserMessage: "Authentication error: Basic Auth required",
verifyUser: (username, password, c: AppContext) => {
const users = (
Array.isArray(c.get("config").basicAuth)
? c.get("config").basicAuth
: [c.get("config").basicAuth]
) as BasicAuth[];
) as BasicAuthType[];
for (const user of users) {
if (user.username === username && user.password === password) {
@@ -122,7 +115,6 @@ export function R2Explorer(config?: R2ExplorerConfig) {
openapi.get("/api/server/config", GetInfo);
openapi.get("/api/buckets", ListBuckets);
openapi.get("/api/buckets/:bucket", ListObjects);
openapi.post("/api/buckets/:bucket/move", MoveObject);
openapi.post("/api/buckets/:bucket/folder", CreateFolder);
@@ -1,29 +0,0 @@
import { OpenAPIRoute } from "chanfana";
import type { AppContext } from "../../types";
export class ListBuckets extends OpenAPIRoute {
schema = {
operationId: "get-bucket-list",
tags: ["Buckets"],
summary: "List buckets",
};
async handle(c: AppContext) {
const buckets = [];
for (const [key, value] of Object.entries(c.env)) {
if (
value.get &&
value.put &&
value.get.toString().includes("function") &&
value.put.toString().includes("function")
) {
buckets.push({ name: key });
}
}
return {
buckets: buckets,
};
}
}
@@ -12,6 +12,19 @@ export class GetInfo extends OpenAPIRoute {
async handle(c: AppContext) {
const { basicAuth, ...config } = c.get("config");
const buckets = [];
for (const [key, value] of Object.entries(c.env)) {
if (
value.get &&
value.put &&
value.get.toString().includes("function") &&
value.put.toString().includes("function")
) {
buckets.push({ name: key });
}
}
return {
version: settings.version,
config: config,
@@ -21,6 +34,7 @@ export class GetInfo extends OpenAPIRoute {
username: c.get("authentication_username"),
}
: undefined,
buckets: buckets,
};
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
import type { CloudflareAccessVariables } from "@hono/cloudflare-access";
import type { Context } from "hono";
export type BasicAuth = {
export type BasicAuthType = {
username: string;
password: string;
};
+8 -8
View File
@@ -80,13 +80,13 @@ importers:
dependencies:
'@hono/cloudflare-access':
specifier: ^0.2.0
version: 0.2.0([email protected]4)
version: 0.2.0([email protected]5)
chanfana:
specifier: ^2.5.1
version: 2.5.1
hono:
specifier: ^4.6.14
version: 4.6.14
specifier: ^4.6.15
version: 4.6.15
postal-mime:
specifier: ^2.3.2
version: 2.3.2
@@ -1848,8 +1848,8 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
[email protected]4:
resolution: {integrity: sha512-j4VkyUp2xazGJ8eCCLN1Vm/bxdvm/j5ZuU9AIjLu9vapn2M44p9L3Ktr9Vnb2RN2QtcR/wVjZVMlT5k7GJQgPw==}
[email protected]5:
resolution: {integrity: sha512-OiQwvAOAaI2JrABBH69z5rsctHDzFzIKJge0nYXgtzGJ0KftwLWcBXm1upJC23/omNRtnqM0gjRMbtXshPdqhQ==}
engines: {node: '>=16.9.0'}
[email protected]:
@@ -3421,9 +3421,9 @@ snapshots:
'@fastify/[email protected]': {}
'@hono/[email protected]([email protected]4)':
'@hono/[email protected]([email protected]5)':
dependencies:
hono: 4.6.14
hono: 4.6.15
'@isaacs/[email protected]':
dependencies:
@@ -4748,7 +4748,7 @@ snapshots:
dependencies:
function-bind: 1.1.2
[email protected]4: {}
[email protected]5: {}
[email protected]:
dependencies: