forked from Kieran/void.cat
Add CORS to api
This commit is contained in:
parent
36d5db3f29
commit
67b5ef2b10
@ -75,7 +75,8 @@ public class AuthController : Controller
|
||||
var claims = new List<Claim>()
|
||||
{
|
||||
new(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||
new(ClaimTypes.Expiration, DateTimeOffset.UtcNow.AddHours(6).ToUnixTimeSeconds().ToString())
|
||||
new(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddHours(6).ToUnixTimeSeconds().ToString()),
|
||||
new(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())
|
||||
};
|
||||
claims.AddRange(user.Roles.Select(a => new Claim(ClaimTypes.Role, a)));
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Prometheus;
|
||||
using VoidCat.Model;
|
||||
using VoidCat.Services;
|
||||
using VoidCat.Services.Abstractions;
|
||||
|
||||
namespace VoidCat.Controllers
|
||||
@ -19,7 +17,7 @@ namespace VoidCat.Controllers
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ResponseCache(Location = ResponseCacheLocation.Client, Duration = 60)]
|
||||
[ResponseCache(Location = ResponseCacheLocation.Any, Duration = 60)]
|
||||
public async Task<GlobalStats> GetGlobalStats()
|
||||
{
|
||||
var bw = await _statsReporter.GetBandwidth();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Newtonsoft.Json;
|
||||
@ -8,6 +9,7 @@ using VoidCat.Services.Abstractions;
|
||||
|
||||
namespace VoidCat.Controllers
|
||||
{
|
||||
[EnableCors(CorsPolicy.Upload)]
|
||||
[Route("upload")]
|
||||
public class UploadController : Controller
|
||||
{
|
||||
@ -25,14 +27,6 @@ namespace VoidCat.Controllers
|
||||
_paywallFactory = paywallFactory;
|
||||
}
|
||||
|
||||
[HttpOptions]
|
||||
public IActionResult UploadFileOptions()
|
||||
{
|
||||
// just return 200 status for pre-flight calls
|
||||
// manging CORS headers is not managed inside void.cat
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[DisableRequestSizeLimit]
|
||||
[DisableFormValueModelBinding]
|
||||
|
@ -10,3 +10,9 @@ public static class Policies
|
||||
{
|
||||
public const string RequireAdmin = "RequireAdmin";
|
||||
}
|
||||
|
||||
public static class CorsPolicy
|
||||
{
|
||||
public const string Default = "default";
|
||||
public const string Upload = "upload";
|
||||
}
|
@ -15,6 +15,8 @@ namespace VoidCat.Model
|
||||
public StrikeApiSettings? Strike { get; init; }
|
||||
|
||||
public SmtpSettings? Smtp { get; init; }
|
||||
|
||||
public List<Uri> CorsOrigins { get; init; } = new();
|
||||
}
|
||||
|
||||
public sealed record TorSettings(Uri TorControl, string PrivateKey, string ControlPassword);
|
||||
|
@ -33,6 +33,24 @@ if (useRedis)
|
||||
services.AddSingleton(cx.GetDatabase());
|
||||
}
|
||||
|
||||
services.AddCors(opt =>
|
||||
{
|
||||
opt.AddPolicy(CorsPolicy.Default, p =>
|
||||
{
|
||||
p.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.WithOrigins(voidSettings.CorsOrigins.Select(a => a.OriginalString).ToArray());
|
||||
});
|
||||
|
||||
opt.AddPolicy(CorsPolicy.Upload, p =>
|
||||
{
|
||||
p.AllowCredentials()
|
||||
.AllowAnyMethod()
|
||||
.WithHeaders("V-Content-Type", "V-Filename", "V-Digest", "Content-Type", "Authorization")
|
||||
.WithOrigins(voidSettings.CorsOrigins.Select(a => a.OriginalString).ToArray());
|
||||
});
|
||||
});
|
||||
|
||||
services.AddRouting();
|
||||
services.AddControllers().AddNewtonsoftJson((opt) =>
|
||||
{
|
||||
@ -112,6 +130,7 @@ app.UseStaticFiles();
|
||||
#endif
|
||||
|
||||
app.UseRouting();
|
||||
app.UseCors(CorsPolicy.Default);
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import moment from "moment";
|
||||
import {Link} from "react-router-dom";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {useEffect, useState} from "react";
|
||||
import {FormatBytes} from "../Util";
|
||||
import {useApi} from "../Api";
|
||||
@ -8,9 +8,8 @@ import {logout} from "../LoginState";
|
||||
import {PagedSortBy, PageSortOrder} from "../Const";
|
||||
import {PageSelector} from "../PageSelector";
|
||||
|
||||
export function FileList(props) {
|
||||
export function FileList() {
|
||||
const {AdminApi} = useApi();
|
||||
const auth = useSelector((state) => state.login.jwt);
|
||||
const dispatch = useDispatch();
|
||||
const [files, setFiles] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
@ -24,7 +23,7 @@ export function FileList(props) {
|
||||
sortBy: PagedSortBy.Date,
|
||||
sortOrder: PageSortOrder.Dsc
|
||||
};
|
||||
let req = await AdminApi.fileList(auth, pageReq);
|
||||
let req = await AdminApi.fileList(pageReq);
|
||||
if (req.ok) {
|
||||
setFiles(await req.json());
|
||||
} else if (req.status === 401) {
|
||||
@ -37,7 +36,7 @@ export function FileList(props) {
|
||||
async function deleteFile(e, id) {
|
||||
e.target.disabled = true;
|
||||
if (window.confirm(`Are you sure you want to delete: ${id}?`)) {
|
||||
let req = await AdminApi.deleteFile(auth, id);
|
||||
let req = await AdminApi.deleteFile(id);
|
||||
if (req.ok) {
|
||||
setFiles({
|
||||
...files,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {useEffect, useState} from "react";
|
||||
import {PagedSortBy, PageSortOrder} from "../Const";
|
||||
import {useApi} from "../Api";
|
||||
@ -8,7 +8,6 @@ import moment from "moment";
|
||||
|
||||
export function UserList() {
|
||||
const {AdminApi} = useApi();
|
||||
const auth = useSelector((state) => state.login.jwt);
|
||||
const dispatch = useDispatch();
|
||||
const [users, setUsers] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
@ -22,7 +21,7 @@ export function UserList() {
|
||||
sortBy: PagedSortBy.Id,
|
||||
sortOrder: PageSortOrder.Asc
|
||||
};
|
||||
let req = await AdminApi.userList(auth, pageReq);
|
||||
let req = await AdminApi.userList(pageReq);
|
||||
if (req.ok) {
|
||||
setUsers(await req.json());
|
||||
} else if (req.status === 401) {
|
||||
|
@ -4,12 +4,12 @@ import {ApiHost} from "./Const";
|
||||
export function useApi() {
|
||||
const auth = useSelector(state => state.login.jwt);
|
||||
|
||||
async function getJson(method, url, body) {
|
||||
async function getJson(method, url, body, token) {
|
||||
let headers = {
|
||||
"Accept": "application/json"
|
||||
};
|
||||
if (auth) {
|
||||
headers["Authorization"] = `Bearer ${auth}`;
|
||||
if (token) {
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
if (body) {
|
||||
headers["Content-Type"] = "application/json";
|
||||
@ -18,20 +18,21 @@ export function useApi() {
|
||||
return await fetch(`${ApiHost}${url}`, {
|
||||
method,
|
||||
headers,
|
||||
mode: "cors",
|
||||
body: body ? JSON.stringify(body) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
AdminApi: {
|
||||
fileList: (pageReq) => getJson("POST", "/admin/file", pageReq),
|
||||
deleteFile: (id) => getJson("DELETE", `/admin/file/${id}`),
|
||||
userList: (pageReq) => getJson("POST", `/admin/user`, pageReq)
|
||||
fileList: (pageReq) => getJson("POST", "/admin/file", pageReq, auth),
|
||||
deleteFile: (id) => getJson("DELETE", `/admin/file/${id}`, undefined, auth),
|
||||
userList: (pageReq) => getJson("POST", `/admin/user`, pageReq, auth)
|
||||
},
|
||||
Api: {
|
||||
stats: () => getJson("GET", "/stats"),
|
||||
fileInfo: (id) => getJson("GET", `/upload/${id}`),
|
||||
setPaywallConfig: (id, cfg) => getJson("POST", `/upload/${id}/paywall`, cfg),
|
||||
setPaywallConfig: (id, cfg) => getJson("POST", `/upload/${id}/paywall`, cfg, auth),
|
||||
createOrder: (id) => getJson("GET", `/upload/${id}/paywall`),
|
||||
getOrder: (file, order) => getJson("GET", `/upload/${file}/paywall/${order}`),
|
||||
login: (username, password) => getJson("POST", `/auth/login`, {username, password}),
|
||||
|
Loading…
Reference in New Issue
Block a user