Skip to content

Commit

Permalink
added encryption and decryption
Browse files Browse the repository at this point in the history
  • Loading branch information
nomandhoni-cs committed Dec 16, 2024
1 parent 3dc5534 commit 61d96ea
Show file tree
Hide file tree
Showing 13 changed files with 430 additions and 62 deletions.
39 changes: 25 additions & 14 deletions components/SpotlightSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useCallback, useRef } from "react";
import { Command, CommandInput } from "./ui/command";
import { ScrollArea } from "./ui/scroll-area";
import TrialRemaining from "./TrialRemaining";

interface SpotlightSearchProps {
onClose: () => void;
Expand Down Expand Up @@ -252,8 +253,8 @@ const SpotlightSearch: React.FC<SpotlightSearchProps> = ({ onClose }) => {
key={section}
className={`flex-1 p-2 capitalize ${
activeSection === section
? "bg-blue-100 text-blue-700 font-semibold"
: "hover:bg-gray-100"
? "bg-[#32CD32] text-black font-semibold"
: "hover:bg-green-300"
}`}
onClick={() => {
setActiveSection(section);
Expand Down Expand Up @@ -281,6 +282,14 @@ const SpotlightSearch: React.FC<SpotlightSearchProps> = ({ onClose }) => {
);
};

// Turncate text if it exceeds the maximum length
const truncateText = (text: string, maxLength: number) => {
if (text.length > maxLength) {
return text.slice(0, maxLength) + "...";
}
return text;
};

// Render result items
const renderResultItems = () => {
const items = filteredResults();
Expand Down Expand Up @@ -323,8 +332,8 @@ const SpotlightSearch: React.FC<SpotlightSearchProps> = ({ onClose }) => {
key={item.id}
className={`flex items-center p-2 rounded-lg border cursor-pointer ${
index === selectedItemIndex && hasArrowKeyPressed
? "bg-blue-100 border-blue-300"
: "hover:bg-gray-50"
? "bg-green-200 border-green-300"
: "hover:bg-green-300"
}`}
onClick={() => {
setHasArrowKeyPressed(true);
Expand All @@ -333,10 +342,12 @@ const SpotlightSearch: React.FC<SpotlightSearchProps> = ({ onClose }) => {
}}
>
{icon}
<div className="flex-grow overflow-hidden">
<div className="truncate">{primaryText}</div>
<div className="text-xs text-gray-500 truncate">
{secondaryText}
<div className="flex-grow overflow-hidden max-w-full">
<div className="truncate whitespace-nowrap overflow-hidden text-ellipsis font-semibold">
{truncateText(primaryText, 90)}
</div>
<div className="text-xs text-gray-500 truncate whitespace-nowrap overflow-hidden text-ellipsis">
{truncateText(secondaryText, 90)}
</div>
</div>
</div>
Expand All @@ -346,15 +357,15 @@ const SpotlightSearch: React.FC<SpotlightSearchProps> = ({ onClose }) => {

return (
<div
className="fixed inset-0 -mt-32 z-50 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4"
className="fixed inset-0 z-50 bg-black/40 flex items-center justify-center p-4 w-full h-full bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-70 "
onClick={onClose}
>
<div
className="w-full max-w-3xl absolute top-[40%] transform transition-all"
className="w-full max-w-3xl absolute top-[20%] transform transition-all"
onClick={(e) => e.stopPropagation()}
>
<div className="flex items-center justify-between mb-1">
<div></div>
<TrialRemaining />

<a
href="https://buymeacoffee.com/nomandhoni"
Expand All @@ -376,14 +387,14 @@ const SpotlightSearch: React.FC<SpotlightSearchProps> = ({ onClose }) => {
</div>

<Command
className="rounded-xl border shadow-2xl bg-white overflow-hidden"
className="rounded-xl border shadow-xl bg-white dark:bg-black overflow-hidden"
onKeyDown={handleKeyDown}
>
{/* Search Input Section */}
<div className="sticky top-0 z-20 bg-white border-b">
<div className="sticky top-0 z-20 bg-white dark:bg-black border-b">
<CommandInput
placeholder="Search tabs, history, bookmarks, downloads, or enter a URL..."
className="h-14 px-4 border-none focus:ring-0"
className="h-16 px-1 border-none focus:ring-0"
value={input}
onValueChange={setInput}
onKeyDown={(e) => {
Expand Down
74 changes: 74 additions & 0 deletions components/TrialRemaining.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useState, useEffect } from "react";
import { decryptData } from "@/lib/cryptoUtils";

const TrialRemaining = () => {
const [installTimeValue, setInstallTimeValue] = useState<Date | null>(null);
const [trialRemaining, setTrialRemaining] = useState<string | null>(null);
const trialPeriod = 30; // 30-day trial

useEffect(() => {
const fetchInstallTime = async () => {
try {
// Fetch and decrypt the installation date from storage
const encryptedInstallTimeString = await storage.getItem<string>(
"sync:installDate"
);

if (encryptedInstallTimeString) {
// Decrypt and parse the installation date
const decryptedInstallTime = await decryptData(
encryptedInstallTimeString
);
const timestamp = parseInt(decryptedInstallTime);
const installDate = new Date(timestamp);
setInstallTimeValue(installDate);

// Calculate the remaining trial period
calculateTrialRemaining(installDate);
} else {
// If no installation time is found, initialize with current date
const currentInstallDate = new Date();
setInstallTimeValue(currentInstallDate);

// Start trial calculation
calculateTrialRemaining(currentInstallDate);
}
} catch (error) {
console.error("Error fetching or saving install date:", error);
}
};

// Calculate the remaining trial days
const calculateTrialRemaining = (installDate: Date) => {
const currentDate = new Date();
const diffTime = currentDate.getTime() - installDate.getTime();
const diffDays = Math.ceil(diffTime / (1000 * 3600 * 24)); // Convert ms to days

const daysRemaining = trialPeriod - diffDays;

if (daysRemaining > 0) {
setTrialRemaining(`${daysRemaining} days`);
} else {
setTrialRemaining("Your trial period has expired.");
}
};

fetchInstallTime();
}, []);

return (
<div className="trial-container">
{installTimeValue ? (
<span className="trial-info text-white">
Trial Remaining: {trialRemaining}
</span>
) : (
<span className="trial-info text-white animate-pulse">
Loading trial information...
</span>
)}
</div>
);
};

export default TrialRemaining;
2 changes: 1 addition & 1 deletion components/ui/command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const CommandInput = React.forwardRef<
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<MagnifyingGlassIcon className="mr-2 h-8 w-8 shrink-0 opacity-50" />
<MagnifyingGlassIcon className="mr-2 h-8 w-8 shrink-0 fill text-[#32CD32]" />
<CommandPrimitive.Input
ref={ref}
className={cn(
Expand Down
51 changes: 51 additions & 0 deletions entrypoints/background.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,59 @@
import { encryptData } from "@/lib/cryptoUtils";
import { installNanoId } from "@/lib/storage";
import { nanoid } from "nanoid";

export default defineBackground(() => {
console.log("Spotlight Search Extension Initialized", {
id: browser.runtime.id,
});

// Utility function to set the encrypted installation date
const setEncryptedInstallDate = async () => {
const currentTimestamp = Date.now().toString();
const encryptedDate = await encryptData(currentTimestamp);
const existingInstallDate = await storage.getItem<number[]>(
"sync:installDate"
);
if (existingInstallDate) {
console.log("Existing installation date found:", existingInstallDate);
return;
}
await storage.setItem("sync:installDate", JSON.stringify(encryptedDate));
console.log("Encrypted installation date stored:", encryptedDate);
};

// Listener for extension installation/updates
browser.runtime.onInstalled.addListener(async (details) => {
console.log("Extension installed/updated:", details);

try {
// Ensure Nano ID is initialized
let nanoId = await installNanoId.getValue();
if (!nanoId) {
await installNanoId.setValue(nanoid()); // Set the value
nanoId = await installNanoId.getValue(); // Retrieve the value after setting
console.log("Nano ID generated:", nanoId);
} else {
console.log("Nano ID already initialized:", nanoId);
}

// Set the encrypted installation date
await setEncryptedInstallDate();

// Set default search engine
const defaultSearchEngineKey = "sync:defaultSearchEngine";
const existingSearchEngine = await storage.getItem<string>(
defaultSearchEngineKey
);
if (!existingSearchEngine) {
await storage.setItem(defaultSearchEngineKey, "google");
console.log("Default search engine set to 'google'");
}
} catch (error) {
console.error("Error during initialization:", error);
}
});

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log("Received message:", message);
const searchTerm = message.searchTerm?.toLowerCase() || "";
Expand Down
3 changes: 2 additions & 1 deletion entrypoints/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default defineContentScript({
cssInjectionMode: "ui",

main(ctx) {
console.log("Script Mounted");
// Create a global event listener for CTRL+M
const handleKeyDown = (event: KeyboardEvent) => {
if ((event.ctrlKey || event.metaKey) && event.key === "m") {
Expand All @@ -29,7 +30,7 @@ async function mountSpotlightSearch(ctx: ContentScriptContext) {
const ui = await createShadowRootUi(ctx, {
name: "spotlight-search",
position: "inline",
anchor: "body",
anchor: "html",
isolateEvents: true,
onMount(container) {
const root = createRoot(container);
Expand Down
98 changes: 62 additions & 36 deletions entrypoints/popup/App.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,76 @@
import { useState } from "react";
import reactLogo from "@/assets/react.svg";
import wxtLogo from "/wxt.svg";
import "./App.css";
import { decryptData } from "@/lib/cryptoUtils";
import { useState, useEffect } from "react";
import logo from "/icon/128.png";

function App() {
const [count, setCount] = useState(0);
const handleSubmit = async (event) => {
event.preventDefault();
// const [nanoId, setNanoId] = useState<string | null>(null);
const [installTimeValue, setInstallTimeValue] = useState<Date | null>(null);

// Make sure browser API is available
if (browser.tabs && typeof browser.tabs.create === "function") {
useEffect(() => {
const fetchStorageData = async () => {
try {
const tab = await browser.tabs.create({ url: "https://blinkeye.app" });
console.log("New tab created:", tab);
// // Fetch Nano ID
// const storedNanoId = await storage.getItem<string>("sync:nanoId");
// setNanoId(storedNanoId || "No Nano ID found");

// Fetch and decrypt installation time
const encryptedInstallTimeString = await storage.getItem<string>(
"sync:installDate"
);
console.log(encryptedInstallTimeString);
if (encryptedInstallTimeString) {
const decryptedInstallTime = await decryptData(
encryptedInstallTimeString
);
console.log(decryptedInstallTime);
const timestamp = parseInt(decryptedInstallTime);
setInstallTimeValue(new Date(timestamp));
} else {
console.log("No install time found");
setInstallTimeValue(null);
}
} catch (error) {
console.error("Error creating tab:", error);
console.error("Error fetching storage data:", error);
}
} else {
console.error("Tabs API is not available.");
}
};
};

fetchStorageData();
}, []);

return (
<>
<div>
<button onClick={handleSubmit}>Open new tab</button>
<a href="https://wxt.dev" target="_blank">
<img src={wxtLogo} className="logo" alt="WXT logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>WXT + React</h1>
<div className="app-container">
<img src={logo} alt="QuickPeek Logo" className="app-logo" />
<h1 className="app-title">QuickPeek</h1>

<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
<p className="instruction">
Use <span className="highlight">CTRL + M</span> /{" "}
<span className="highlight">Command + M</span> to launch the search
</p>

{/* <div className="info">
<h2>Nano ID</h2>
<p>{nanoId || "Loading..."}</p>
</div> */}

<div className="info">
<h2>Installation Time</h2>
<p>
{installTimeValue
? installTimeValue.toLocaleString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
timeZoneName: "short",
})
: "No install time found"}
</p>
</div>
</div>
<p className="read-the-docs">
Click on the WXT and React logos to learn more
</p>
</>
</div>
);
}

Expand Down
12 changes: 6 additions & 6 deletions entrypoints/popup/main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './style.css';
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./style.css";

ReactDOM.createRoot(document.getElementById('root')!).render(
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
</React.StrictMode>
);
Loading

0 comments on commit 61d96ea

Please sign in to comment.