mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-26 03:39:28 -04:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de1e2431ad | ||
|
|
92b68d3f9d | ||
|
|
c39651415d | ||
|
|
7dae90f1e2 |
@@ -27,6 +27,7 @@ use errors::AnyhowResult;
|
||||
|
||||
pub mod billing;
|
||||
pub mod configs;
|
||||
pub mod error;
|
||||
pub mod http_server;
|
||||
pub mod state;
|
||||
pub mod threads;
|
||||
|
||||
@@ -30,6 +30,7 @@ use crate::configs::static_api_tokens::StaticApiTokenSet;
|
||||
|
||||
pub mod billing;
|
||||
pub mod configs;
|
||||
pub mod error;
|
||||
pub mod http_server;
|
||||
pub mod state;
|
||||
pub mod threads;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
/// Any generic errors arising internally.
|
||||
/// An error class that we do not expose via the API.
|
||||
/// This should be massaged before we send it to the user.
|
||||
#[derive(Debug)]
|
||||
pub enum InternalError {
|
||||
/// Issue with HMAC decoding
|
||||
/// This is typically when using development cookies against production,
|
||||
/// or vice versa.
|
||||
VisitorCookieError(String),
|
||||
|
||||
/// Decode error with AVT cookie missing a required field.
|
||||
VisitorCookieMissingField(&'static str),
|
||||
|
||||
/// Catch instances of anyhow::Error.
|
||||
AnyhowError(anyhow::Error),
|
||||
}
|
||||
|
||||
impl Error for InternalError {}
|
||||
|
||||
impl Display for InternalError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
InternalError::VisitorCookieError(reason) => write!(f, "Visitor cookie error: {:?}", reason),
|
||||
InternalError::VisitorCookieMissingField(field) => write!(f, "Visitor cookie missing field: {}", field),
|
||||
InternalError::AnyhowError(err) => write!(f, "Anyhow error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for InternalError {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
InternalError::AnyhowError(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod internal_error;
|
||||
+4
-4
@@ -4,12 +4,12 @@ use actix_web::HttpRequest;
|
||||
use anyhow::anyhow;
|
||||
use log::warn;
|
||||
|
||||
use crate::error::internal_error::InternalError;
|
||||
use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload;
|
||||
use cookies::jwt_signer::JwtSigner;
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
|
||||
use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload;
|
||||
|
||||
const VISITOR_COOKIE_NAME : &str = "visitor";
|
||||
|
||||
/// Handle "anonymous visitor tracking" cookies.
|
||||
@@ -70,7 +70,7 @@ impl AvtCookieManager {
|
||||
Ok(payload)
|
||||
}
|
||||
|
||||
pub fn decode_cookie_payload_from_request(&self, request: &HttpRequest) -> AnyhowResult<Option<AvtCookiePayload>> {
|
||||
pub fn decode_cookie_payload_from_request(&self, request: &HttpRequest) -> Result<Option<AvtCookiePayload>, InternalError> {
|
||||
let cookie = match request.cookie(VISITOR_COOKIE_NAME) {
|
||||
None => return Ok(None),
|
||||
Some(cookie) => cookie,
|
||||
@@ -79,7 +79,7 @@ impl AvtCookieManager {
|
||||
match self.decode_cookie_payload(&cookie) {
|
||||
Err(e) => {
|
||||
warn!("Visitor cookie decode error: {:?}", e);
|
||||
Err(anyhow!("Could not decode visitor cookie: {:?}", e))
|
||||
Err(InternalError::VisitorCookieError(e.to_string()))
|
||||
},
|
||||
Ok(payload) => Ok(Some(payload)),
|
||||
}
|
||||
|
||||
+8
-9
@@ -1,9 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
use errors::AnyhowResult;
|
||||
use crate::error::internal_error::InternalError;
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
|
||||
/**
|
||||
@@ -38,18 +36,19 @@ impl AvtCookiePayload {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_map(map: BTreeMap<String, String>) -> AnyhowResult<Self> {
|
||||
pub fn from_map(map: BTreeMap<String, String>) -> Result<Self, InternalError> {
|
||||
let avt_token = map.get("avt_token")
|
||||
.ok_or(anyhow!("avt_token not present"))?
|
||||
.to_string();
|
||||
.ok_or_else(|| InternalError::VisitorCookieMissingField("avt_token"))?;
|
||||
|
||||
let cookie_version = map
|
||||
.get("cookie_version")
|
||||
.ok_or(anyhow!("avt_token not present"))?;
|
||||
.ok_or_else(|| InternalError::VisitorCookieMissingField("cookie_version"))?;
|
||||
|
||||
let avt_token = AnonymousVisitorTrackingToken::new_from_str(&avt_token);
|
||||
let avt_token = AnonymousVisitorTrackingToken::new_from_str(avt_token);
|
||||
|
||||
let cookie_version = u32::from_str(cookie_version)?;
|
||||
let cookie_version = u32::from_str(cookie_version)
|
||||
.map_err(|e| InternalError::VisitorCookieError(
|
||||
format!("invalid integer for cookie_version: {:?}, version: {}", e, cookie_version)))?;
|
||||
|
||||
Ok(AvtCookiePayload {
|
||||
avt_token,
|
||||
|
||||
@@ -92,6 +92,7 @@ use crate::util::troll_user_bans::troll_user_ban_list::TrollUserBanList;
|
||||
|
||||
pub mod billing;
|
||||
pub mod configs;
|
||||
pub mod error;
|
||||
pub mod http_server;
|
||||
pub mod state;
|
||||
pub mod threads;
|
||||
|
||||
@@ -13,3 +13,17 @@ export const normalizeCanvas = (canvas: HTMLCanvasElement, width: number, height
|
||||
ctx.drawImage(canvas, 0, 0, width, height);
|
||||
return newCanvas;
|
||||
}
|
||||
|
||||
export const drawAlphaMask = (canvas: OffscreenCanvas, width: number, height: number) => {
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) {
|
||||
throw new Error("Failed to get canvas context");
|
||||
}
|
||||
|
||||
// Fill the entire screen with black and composite to keep non-transparent pixels
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = "source-in";
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useUndoRedoHotkeys } from "../PageDraw/hooks/useUndoRedoHotkeys";
|
||||
import PromptEditor from "./PromptEditor/PromptEditor";
|
||||
import { ActiveEditTool, useEditStore } from "./stores/EditState";
|
||||
import { EditPaintSurface } from "./EditPaintSurface";
|
||||
import { normalizeCanvas } from "../../Helpers/CanvasHelpers";
|
||||
import { drawAlphaMask, normalizeCanvas } from "../../Helpers/CanvasHelpers";
|
||||
import { BaseImageSelector, BaseSelectorImage } from "./BaseImageSelector";
|
||||
import DrawToolControlBar from "./DrawToolControlBar";
|
||||
import {
|
||||
@@ -187,6 +187,10 @@ const PageEdit = () => {
|
||||
rect.height(),
|
||||
);
|
||||
|
||||
// Convert colored canvas to alpha mask
|
||||
// NOTE: This isn't needed because the tauri backend uses the alpha channel anyway
|
||||
// drawAlphaMask(fittedCanvas, rect.width(), rect.height());
|
||||
|
||||
const blob = await fittedCanvas.convertToBlob({ type: "image/png" });
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
|
||||
@@ -370,7 +374,7 @@ const PageEdit = () => {
|
||||
}}
|
||||
//fillColor={store.fillColor}
|
||||
activeTool={store.activeTool}
|
||||
brushColor={store.brushColor}
|
||||
brushColor={"rgba(39, 187, 245, 0.54)"}
|
||||
brushSize={store.brushSize}
|
||||
onSelectionChange={setIsSelecting}
|
||||
stageRef={stageRef}
|
||||
|
||||
Reference in New Issue
Block a user