Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@tanstack/react-router-ssr-query": "^1.166.12",
"@tanstack/react-start": "^1.167.61",
"@tanstack/router-plugin": "^1.167.32",
"koffi": "^2.16.2",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check latest koffi version on npm
npm view koffi version

# Check for security advisories
npm audit --package-lock-only 2>/dev/null || echo "Run 'npm audit' after npm install to check for vulnerabilities"

# Check GitHub advisories for koffi
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "koffi") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Repository: AOSSIE-Org/Rein

Length of output: 2722


Update koffi to the latest major and re-check audits.

  • package.json pins koffi as ^2.16.2, but npm view koffi version shows the latest published version is 3.0.2 (the current range won’t include v3).
  • GitHub Advisory search returned no known koffi vulnerabilities, and npm audit --package-lock-only didn’t report issues for koffi.
  • Run npm install and then npm audit so the audit reflects the updated dependency in the lockfile.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 26, Update the koffi dependency in package.json from
"^2.16.2" to the current major "^3.0.2" (edit the "koffi" entry), then run npm
install to update package-lock.json and finally run npm audit (or npm audit
--package-lock-only) to ensure the lockfile reflects the new version and to
re-check for vulnerabilities; commit the updated package.json and
package-lock.json.

"lucide-react": "^0.561.0",
"nitro": "^3.0.260429-beta",
"nitro-nightly": "^3.0.1-20260501-164602-aee73f19",
Expand Down
4 changes: 2 additions & 2 deletions src/components/Trackpad/ScreenMirror.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"use client"

import type React from "react"
import { useRef } from "react"
import { useConnection } from "../../contexts/ConnectionProvider"
import { useMirrorStream } from "../../hooks/useMirrorStream"

interface ScreenMirrorProps {
scrollMode: boolean
isTracking: boolean
handlers: React.HTMLAttributes<HTMLDivElement>
canvasRef: React.RefObject<HTMLCanvasElement | null>
}

const TEXTS = {
Expand All @@ -20,9 +20,9 @@ export const ScreenMirror = ({
scrollMode,
isTracking,
handlers,
canvasRef,
}: ScreenMirrorProps) => {
const { wsRef, status } = useConnection()
const canvasRef = useRef<HTMLCanvasElement>(null)
const { hasFrame } = useMirrorStream(wsRef, canvasRef, status)

return (
Expand Down
10 changes: 9 additions & 1 deletion src/hooks/useCaptureProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export function useCaptureProvider(wsRef: React.RefObject<WebSocket | null>) {
}
setIsSharing(false)
}
const getConfig = () => ({
sensitivity:
Number.parseFloat(localStorage.getItem("rein_sensitivity") || "1.0") ||
1.0,
invertScroll: localStorage.getItem("rein_invert") === "true" || false,
})

const captureFrame = () => {
if (!videoRef.current || !canvasRef.current || !wsRef.current) return
Expand Down Expand Up @@ -103,7 +109,9 @@ export function useCaptureProvider(wsRef: React.RefObject<WebSocket | null>) {
setIsSharing(true)

if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
wsRef.current.send(JSON.stringify({ type: "start-provider" }))
wsRef.current.send(
JSON.stringify({ type: "start-provider", config: getConfig() }),
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// Start capture loop (approx 12 FPS)
Expand Down
16 changes: 15 additions & 1 deletion src/hooks/useRemoteConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ export const useRemoteConnection = () => {
keys: msg,
})
}
const sendConfigUpdate = (sensitivity: number, invertScroll: boolean) => {
send({
type: "update-settings",
config: { sensitivity, invertScroll },
})
}

return { status, platform, send, sendCombo, wsRef, subscribe }
return {
status,
platform,
send,
sendCombo,
sendConfigUpdate,
wsRef,
subscribe,
}
}
67 changes: 18 additions & 49 deletions src/hooks/useTrackpadGesture.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import { useEffect, useRef, useState } from "react"
import {
PINCH_THRESHOLD,
TOUCH_MOVE_THRESHOLD,
TOUCH_TIMEOUT,
calculateAccelerationMult,
} from "../utils/math"

interface TrackedTouch {
identifier: number
Expand All @@ -30,8 +24,6 @@ const BUTTON_MAP: Record<number, "left" | "right" | "middle"> = {
export const useTrackpadGesture = (
send: (msg: unknown) => void,
scrollMode: boolean,
sensitivity = 1.5,
invertScroll = false,
axisThreshold = 2.5,
) => {
const [isTracking, setIsTracking] = useState(false)
Expand All @@ -43,20 +35,20 @@ export const useTrackpadGesture = (
const releasedCount = useRef(0)
const dragging = useRef(false)
const draggingTimeout = useRef<NodeJS.Timeout | null>(null)
const TOUCH_MOVE_THRESHOLD = [10, 15, 15]
const TOUCH_TIMEOUT = 250
const PINCH_THRESHOLD = 10
const lastPinchDist = useRef<number | null>(null)
const pinching = useRef(false)

const processMovement = (sumX: number, sumY: number) => {
const touchCount = ongoingTouches.current.size

if (dragging.current) {
send({
type: "move",
dx: Math.round(sumX * sensitivity * 10) / 10,
dy: Math.round(sumY * sensitivity * 10) / 10,
})
send({ type: "move", dx: sumX, dy: sumY })
return
}
const invertMult = invertScroll ? -1 : 1

if (!scrollMode && touchCount === 2) {
const touches = Array.from(ongoingTouches.current.values())
const dist = getTouchDistance(touches[0], touches[1])
Expand All @@ -65,38 +57,23 @@ export const useTrackpadGesture = (
if (pinching.current || Math.abs(delta) > PINCH_THRESHOLD) {
pinching.current = true
lastPinchDist.current = dist
send({ type: "zoom", delta: delta * sensitivity * invertMult })
send({ type: "zoom", delta })
} else {
lastPinchDist.current = dist
send({
type: "scroll",
dx: -sumX * sensitivity * invertMult,
dy: -sumY * sensitivity * invertMult,
})
send({ type: "scroll", dx: -sumX, dy: -sumY })
}
} else if (scrollMode || touchCount === 2) {
let scrollDx = sumX
let scrollDy = sumY
let dx = sumX,
dy = sumY
if (scrollMode) {
const absDx = Math.abs(scrollDx)
const absDy = Math.abs(scrollDy)
if (absDx > absDy * axisThreshold) {
scrollDy = 0
} else if (absDy > absDx * axisThreshold) {
scrollDx = 0
}
const absDx = Math.abs(dx),
absDy = Math.abs(dy)
if (absDx > absDy * axisThreshold) dy = 0
else if (absDy > absDx * axisThreshold) dx = 0
}
send({
type: "scroll",
dx: Math.round(-scrollDx * sensitivity * 10 * invertMult) / 10,
dy: Math.round(-scrollDy * sensitivity * 10 * invertMult) / 10,
})
send({ type: "scroll", dx: -dx, dy: -dy })
} else if (touchCount === 1) {
send({
type: "move",
dx: Math.round(sumX * sensitivity * 10) / 10,
dy: Math.round(sumY * sensitivity * 10) / 10,
})
send({ type: "move", dx: sumX, dy: sumY })
}
}

Expand Down Expand Up @@ -173,18 +150,10 @@ export const useTrackpadGesture = (
moved.current = true
}
}

// Calculate delta with acceleration
const dx = touch.pageX - tracked.pageX
const dy = touch.pageY - tracked.pageY
const timeDelta = e.timeStamp - tracked.timeStamp

if (timeDelta > 0) {
const speedX = (Math.abs(dx) / timeDelta) * 1000
const speedY = (Math.abs(dy) / timeDelta) * 1000
sumX += dx * calculateAccelerationMult(speedX)
sumY += dy * calculateAccelerationMult(speedY)
}
sumX += dx
sumY += dy

// Update tracked position
tracked.pageX = touch.pageX
Expand Down
68 changes: 37 additions & 31 deletions src/routes/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createFileRoute } from "@tanstack/react-router"
import QRCode from "qrcode"
import { useEffect, useState } from "react"
import { useEffect, useState, useRef } from "react"
import { APP_CONFIG, THEMES } from "../config"
import serverConfig from "../server-config.json"

import { useRemoteConnection } from "../hooks/useRemoteConnection"
export const Route = createFileRoute("/settings")({
component: SettingsPage,
})
Expand All @@ -14,26 +14,26 @@ function SettingsPage() {
String(serverConfig.frontendPort),
)
const [originalPort] = useState(String(serverConfig.frontendPort))

const serverConfigChanged = frontendPort !== originalPort

const sendConfigUpdate = useRemoteConnection().sendConfigUpdate
// Client Side Settings (LocalStorage)
const [invertScroll, setInvertScroll] = useState(() => {
if (typeof window === "undefined") return false
const [initialSensitivity, initialInvert] = (() => {
try {
const saved = localStorage.getItem("rein_invert")
return saved === "true"
const savedSensitivity = localStorage.getItem("rein_sensitivity")
const parsed = savedSensitivity
? Number.parseFloat(savedSensitivity)
: Number.NaN
return [
Number.isFinite(parsed) ? parsed : 1.0,
localStorage.getItem("rein_invert") === "true",
] as const
} catch {
return false
return [1.0, false] as const
}
})
})()

const [sensitivity, setSensitivity] = useState(() => {
if (typeof window === "undefined") return 1.0
const saved = localStorage.getItem("rein_sensitivity")
const parsed = saved ? Number.parseFloat(saved) : Number.NaN
return Number.isFinite(parsed) ? parsed : 1.0
})
const sensitivity = useRef(initialSensitivity)
const invertScroll = useRef(initialInvert)

const [theme, setTheme] = useState(() => {
if (typeof window === "undefined") return THEMES.DEFAULT
Expand All @@ -48,6 +48,16 @@ function SettingsPage() {
})

const [qrData, setQrData] = useState("")
const setConfig = (sensitivity_val: number, invertedScroll_val: boolean) => {
sensitivity.current = sensitivity_val
invertScroll.current = invertedScroll_val
localStorage.setItem("rein_sensitivity", String(sensitivity_val))
localStorage.setItem("rein_invert", JSON.stringify(invertedScroll_val))
const timer = setTimeout(() => {
sendConfigUpdate(sensitivity.current, invertScroll.current)
}, 300)
return () => clearTimeout(timer)
}

// Load initial state (IP is not stored in localStorage; only sensitivity, invert, theme are client settings)
const [authToken, setAuthToken] = useState(() => {
Expand Down Expand Up @@ -112,15 +122,6 @@ function SettingsPage() {
}
}, [])

// Effect: Update LocalStorage when settings change
useEffect(() => {
localStorage.setItem("rein_sensitivity", String(sensitivity))
}, [sensitivity])

useEffect(() => {
localStorage.setItem("rein_invert", JSON.stringify(invertScroll))
}, [invertScroll])

// Effect: Theme
useEffect(() => {
if (typeof window === "undefined") return
Expand Down Expand Up @@ -181,19 +182,22 @@ function SettingsPage() {
<label className="label mb-3" htmlFor="sensitivity-slider">
<span className="label-text">Mouse Sensitivity</span>
<span className="label-text-alt font-mono">
{sensitivity.toFixed(1)}x
{sensitivity.current.toFixed(1)}x
</span>
</label>

<input
type="range"
id="sensitivity-slider"
min="0.1"
max="3.0"
max="6.0"
step="0.1"
value={sensitivity}
defaultValue={sensitivity.current}
onChange={(e) =>
setSensitivity(Number.parseFloat(e.target.value))
setConfig(
parseFloat(e.target.value) || 1.0,
invertScroll.current,
)
}
className="range range-primary range-sm w-full"
/>
Expand All @@ -215,8 +219,10 @@ function SettingsPage() {
id="invert-scroll-toggle"
type="checkbox"
className="toggle toggle-primary"
checked={invertScroll}
onChange={(e) => setInvertScroll(e.target.checked)}
defaultChecked={invertScroll.current}
onChange={(e) =>
setConfig(sensitivity.current, e.target.checked)
}
/>
</label>

Expand Down
Loading
Loading