Skip to content

Commit

Permalink
fix unauthorized metric-access + image-caching
Browse files Browse the repository at this point in the history
  • Loading branch information
Paulsenik committed Dec 13, 2024
1 parent b1b1a4c commit 1ee493b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -65,18 +67,30 @@ public ResponseEntity<Optional<ShopItem>> get(@RequestParam String id) {
}

@GetMapping("/item/picture")
public ResponseEntity<FileSystemResource> getDisplayImage(@RequestParam String id) {
public ResponseEntity<FileSystemResource> getDisplayImage(@RequestParam String id,
@RequestHeader(value = HttpHeaders.IF_MODIFIED_SINCE, required = false) String ifModifiedSince) {
Optional<ShopItem> item = itemRepository.findById(id);
if (item.isPresent()) {

Optional<File> file = fileStorageService.getItemPicture(item.get());
if (file.isPresent()) {
FileSystemResource resource = new FileSystemResource(file.get());
Optional<File> fileO = fileStorageService.getItemPicture(item.get());
if (fileO.isPresent()) {
File file = fileO.get();
long lastModified = file.lastModified();

// Handle last modified check
if (ifModifiedSince != null && Long.parseLong(ifModifiedSince) >= lastModified) {
return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();
}

FileSystemResource resource = new FileSystemResource(file);

return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + file.get().getName() + "\"")
"attachment; filename=\"" + file.getName() + "\"")
.header(HttpHeaders.CACHE_CONTROL, "max-age=31536000, public, immutable")
.header(HttpHeaders.ETAG, String.valueOf(file.lastModified()))
.header(HttpHeaders.LAST_MODIFIED, String.valueOf(file.lastModified()))
.body(resource);
} else {
return ResponseEntity.noContent().build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class WebConfig implements WebMvcConfigurer {

public static final String[] AUTH_WHITELIST = {
"/api/authentication",
"/api/statistics/metric/**",
"/api/shop/item/picture",
};

public static final String[] USER_SPACE = {
Expand All @@ -44,6 +44,7 @@ public class WebConfig implements WebMvcConfigurer {
"/api/transaction/me",
"/api/invoice/me",
"/api/shop/item/**",
"/api/statistics/metric/**",
};

public static final String[] KIOSK_SPACE = {
Expand Down
57 changes: 24 additions & 33 deletions frontend/src/Queries.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import axios from "axios";
import { ShopHistoryEntryPage } from "./Types/ShopHistory";
import { ShopItem } from "./Types/ShopItem";
import { AuthorizedUser, User } from "./Types/User";
import { getEncodedCredentials, setAuthorizedUser } from "./SessionInfo";
import { InvoicePage } from "./Types/Invoice";
import { TransactionPage } from "./Types/Transaction";
import { UserMetricType as UserMetricType, UserMetricEntry as UserMetricEntry, TimeSpan, ItemMetricType as ItemMetricType, ItemMetricEntry as ItemMetricEntry, CompositeMetricEntry as CompositeMetricEntry, CompositeMetricType as CompositeMetricType } from "./Types/Statistics";
import { toast } from "react-toastify";
import {ShopHistoryEntryPage} from "./Types/ShopHistory";
import {ShopItem} from "./Types/ShopItem";
import {AuthorizedUser, User} from "./Types/User";
import {getEncodedCredentials, setAuthorizedUser} from "./SessionInfo";
import {InvoicePage} from "./Types/Invoice";
import {TransactionPage} from "./Types/Transaction";
import {
CompositeMetricEntry as CompositeMetricEntry,
CompositeMetricType as CompositeMetricType,
ItemMetricEntry as ItemMetricEntry,
ItemMetricType as ItemMetricType,
TimeSpan,
UserMetricEntry as UserMetricEntry,
UserMetricType as UserMetricType
} from "./Types/Statistics";
import {toast} from "react-toastify";

export const apiUrl = import.meta.env.VITE_API_URL || "http://localhost:8081";

Expand Down Expand Up @@ -182,9 +190,9 @@ export async function createTransaction(receiver: User, value: string, actionTyp
}

export async function getAllTransactions(
size: number,
page: number,
receiverId: string | undefined
size: number,
page: number,
receiverId: string | undefined
): Promise<TransactionPage | undefined> {
const params = receiverId ? "&receiverId=" + receiverId : "";

Expand Down Expand Up @@ -418,24 +426,7 @@ export async function uploadItemDisplayPicture(item: ShopItem, file: File): Prom
}

export async function getItemDisplayPicture(item: ShopItem): Promise<string | undefined> {
try {
const result = await fetch(apiUrl + `/api/shop/item/picture?id=${item.id}`, {
method: "GET",
headers: {
Authorization: `Basic ${getEncodedCredentials()}`,
"Content-Type": "application/json",
},
});

if (result.ok && result.status === 200) {
const blob = await result.blob();
return URL.createObjectURL(blob);
}
} catch (error) {
// If there's a network error or any other error, return null
return undefined;
}
return undefined;
return `${apiUrl}/api/shop/item/picture?id=${item.id}`;
}

export async function getPersonalInvoices(): Promise<InvoicePage | undefined> {
Expand All @@ -459,12 +450,12 @@ export async function getPersonalInvoices(): Promise<InvoicePage | undefined> {
}

export async function getAllInvoices(
page: number,
userId: string | undefined,
mailed: boolean | undefined
page: number,
userId: string | undefined,
mailed: boolean | undefined
): Promise<InvoicePage | undefined> {
const params =
(userId ? "&userId=" + userId : "") + (mailed === undefined ? "" : "&mailed=" + (mailed ? "true" : "false"));
(userId ? "&userId=" + userId : "") + (mailed === undefined ? "" : "&mailed=" + (mailed ? "true" : "false"));

try {
const response = await fetch(`${apiUrl}/api/invoice/list?s=20&p=` + page + params, {
Expand Down

0 comments on commit 1ee493b

Please sign in to comment.