Add AnyClip integration tools and extracted source code
- Add authentication scripts with SubtleCrypto password encryption - Add sourcemap extraction pipeline (update-urls, download-sourcemaps, extract-sources) - Add Playwright API interception script for monetization endpoints - Document two-step auth flow with JWT tokens and dual cookies - Move extracted source from root to anyclip/ directory - Add project configuration (.env.example, .gitignore, CLAUDE.md)
This commit is contained in:
111
scripts/crypto.ts
Normal file
111
scripts/crypto.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Reimplementation of string-crypto v2 encryption
|
||||
* Uses Node's built-in crypto module (works in Bun too)
|
||||
*/
|
||||
|
||||
import {
|
||||
randomBytes,
|
||||
pbkdf2Sync,
|
||||
createCipheriv,
|
||||
createDecipheriv,
|
||||
} from "crypto";
|
||||
|
||||
const KEYLEN = 256 / 8; // 32 bytes for aes-256
|
||||
|
||||
interface DeriveKeyOpts {
|
||||
salt?: string;
|
||||
iterations?: number;
|
||||
digest?: string;
|
||||
}
|
||||
|
||||
const defaultOpts: DeriveKeyOpts = {
|
||||
salt: "s41t",
|
||||
iterations: 1,
|
||||
digest: "sha512",
|
||||
};
|
||||
|
||||
export function deriveKey(password: string, options?: DeriveKeyOpts): Buffer {
|
||||
const { salt, iterations, digest } = { ...defaultOpts, ...options };
|
||||
return pbkdf2Sync(password, salt!, iterations!, KEYLEN, digest!);
|
||||
}
|
||||
|
||||
export function encryptString(str: string, password: string): string {
|
||||
const derivedKey = deriveKey(password);
|
||||
const iv = randomBytes(16);
|
||||
|
||||
const cipher = createCipheriv("aes-256-gcm", derivedKey, iv);
|
||||
|
||||
let encryptedBase64 = cipher.update(str, "utf8", "base64");
|
||||
encryptedBase64 += cipher.final("base64");
|
||||
|
||||
// Convert base64 to hex (this is the v2 quirk)
|
||||
const encryptedHex = Buffer.from(encryptedBase64).toString("hex");
|
||||
const ivHex = iv.toString("hex");
|
||||
|
||||
return `${ivHex}:${encryptedHex}`;
|
||||
}
|
||||
|
||||
export function decryptString(encryptedStr: string, password: string): string {
|
||||
const derivedKey = deriveKey(password);
|
||||
const [ivHex, encryptedHex] = encryptedStr.split(":");
|
||||
|
||||
const iv = Buffer.from(ivHex, "hex");
|
||||
const encryptedBase64 = Buffer.from(encryptedHex, "hex").toString();
|
||||
|
||||
const decipher = createDecipheriv("aes-256-gcm", derivedKey, iv);
|
||||
|
||||
let decrypted = decipher.update(encryptedBase64, "base64", "utf8");
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
// Test
|
||||
if (import.meta.main) {
|
||||
// Load .env
|
||||
const envFile = Bun.file(".env");
|
||||
if (await envFile.exists()) {
|
||||
const envContent = await envFile.text();
|
||||
for (const line of envContent.split("\n")) {
|
||||
const [key, ...valueParts] = line.split("=");
|
||||
if (key && valueParts.length) {
|
||||
process.env[key.trim()] = valueParts.join("=").trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const email = process.env.ANYCLIP_EMAIL || process.env.ANYCLIP_USER;
|
||||
const plaintext = process.env.ANYCLIP_PASSWORD;
|
||||
|
||||
if (!email || !plaintext) {
|
||||
console.error("Set ANYCLIP_EMAIL and ANYCLIP_PASSWORD in .env");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const salt = "$2b$04$wwky7rvtr6BFNaCqntwyie";
|
||||
const encrypted = encryptString(plaintext, salt);
|
||||
console.log("Encrypted:", encrypted);
|
||||
|
||||
// Test with API
|
||||
console.log("\nTesting with AnyClip API...");
|
||||
const response = await fetch(
|
||||
"https://videomanager-api.anyclip.com/public/auth/login",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password: encrypted,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
console.log("Status:", response.status);
|
||||
if (response.ok) {
|
||||
console.log("✅ Works without string-crypto library!");
|
||||
} else {
|
||||
const text = await response.text();
|
||||
console.log("Response:", text);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user