diff --git a/browser_test_proving/bun.lockb b/browser_test_proving/bun.lockb index 1b34759..de5aa6f 100755 Binary files a/browser_test_proving/bun.lockb and b/browser_test_proving/bun.lockb differ diff --git a/browser_test_proving/package.json b/browser_test_proving/package.json index ed696eb..1e4de46 100644 --- a/browser_test_proving/package.json +++ b/browser_test_proving/package.json @@ -15,7 +15,7 @@ "dependencies": { "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@zk-email/helpers": "^6.1.3", - "@zk-email/sdk": "file:/Users/dimitridumonet/Code/zkemail/zk-email-sdk-js/zk-email-sdk-1.1.0-51.tgz", + "@zk-email/sdk": "1.1.0-56", "buffer": "^6.0.3", "crypto-browserify": "^3.12.1", "localforage": "^1.10.0", diff --git a/browser_test_proving/src/loginWithMicrosoft.ts b/browser_test_proving/src/loginWithMicrosoft.ts index 8d225b4..b0b8563 100644 --- a/browser_test_proving/src/loginWithMicrosoft.ts +++ b/browser_test_proving/src/loginWithMicrosoft.ts @@ -1,4 +1,4 @@ -import zkeSdk, { FetchEmailOptions, Outlook } from "../../src/index"; +import zkeSdk, { FetchEmailOptions, Outlook, parseEmail, testBlueprint } from "../../src/index"; // import zkeSdk, { FetchEmailOptoins, Gmail } from "../../src/index"; export function setupLoginWithMicrosoft(element: HTMLElement) { @@ -8,7 +8,7 @@ export function setupLoginWithMicrosoft(element: HTMLElement) { const loginButton = element.querySelector("button"); if (loginButton) { loginButton.addEventListener("click", async () => { - const blueprint = await sdk.getBlueprintById("963fbbe8-7f08-4a9c-8608-f378b144aec3"); + const blueprint = await sdk.getBlueprintById("fcbcc3e2-b615-4ae5-bc72-616996a74e18"); // const blueprint = await sdk.getBlueprintById("008b5da5-fbda-4445-b7df-6b0c6dde4bb1"); // const blueprint2 = await sdk.getBlueprintById("0935faed-002d-4b94-8cbf-476b3b05d9a6"); @@ -20,7 +20,15 @@ export function setupLoginWithMicrosoft(element: HTMLElement) { console.log("after authorize: ", outlook); const emails = await outlook.fetchEmails([blueprint]); - console.log("emails: ", emails); + + const email = await outlook.fetchEmailRawById(emails[0].emailMessageId); + console.log("email: ", email); + + + const parsedEmail = await parseEmail(email.decodedContents); + // await testBlueprint(email.rawEmail, blueprint?.props!); + + console.log("parsedEmail: ", parsedEmail); let moreEmails = await outlook.fetchMore(); console.log("moreEmails: ", moreEmails); diff --git a/browser_test_proving/src/main.ts b/browser_test_proving/src/main.ts index 97a15da..a8c2a8f 100644 --- a/browser_test_proving/src/main.ts +++ b/browser_test_proving/src/main.ts @@ -2,7 +2,7 @@ import "./style.css"; import { setupProver } from "./prover.ts"; import { setupLoginWithGoogle } from "./loginWithGoogle.ts"; import { setupLoginWithMicrosoft } from "./loginWithMicrosoft.ts"; -import { setupNoirProver } from "./noirProver.ts"; +// import { setupNoirProver } from "./noirProver.ts"; document.querySelector("#app")!.innerHTML = `
@@ -33,4 +33,4 @@ document.querySelector("#app")!.innerHTML = ` setupProver(document.querySelector("#prover")!); setupLoginWithGoogle(document.querySelector("#lwg")!); setupLoginWithMicrosoft(document.querySelector("#lwm")!); -setupNoirProver(document.querySelector("#noir-prover")!); +// setupNoirProver(document.querySelector("#noir-prover")!); diff --git a/browser_test_proving/src/noirProver.ts b/browser_test_proving/src/noirProver.ts index c188110..c814701 100644 --- a/browser_test_proving/src/noirProver.ts +++ b/browser_test_proving/src/noirProver.ts @@ -1,151 +1,151 @@ -import zkeSdk, { GenerateProofOptions } from "../../src"; -import { initNoirWasm } from "@zk-email/sdk/initNoirWasm"; - -export function setupNoirProver(element: HTMLElement) { - const sdk = zkeSdk({ baseUrl: "http://127.0.0.1:8080" }); - // const sdk = zkeSdk({ baseUrl: "https://dev-conductor.zk.email" }); - - const proveButton = element.querySelector("button"); - if (proveButton) { - proveButton.addEventListener("click", async () => { - try { - console.log("getting blueprint"); - // const blueprint = await sdk.getBlueprintById("008b5da5-fbda-4445-b7df-6b0c6dde4bb1"); - const blueprint = await sdk.getBlueprintById("58a1b5c0-6633-4eb0-9fa8-9e5d605069ab"); - - console.log("blueprint: ", blueprint); - - const prover = blueprint.createProver({ isLocal: true }); - console.log("prover"); - console.log("typeof prover", typeof prover); - - const eml = await getEml(); - - const isValidEml = await blueprint.validateEmail(eml!); - - console.log("isValidEml: ", isValidEml); - - // console.log("putting in eml: ", eml); - const externalInputs = { - name: "name", - value: "master", - maxLength: 32, - }; - const noirWasm = await initNoirWasm(); - const options: GenerateProofOptions = { noirWasm }; - console.log("got the options: ", options); - - const proof = await prover.generateProof(eml!, [externalInputs], options); - console.log("got the noir proof: ", proof); - - // const proof = await prover.generateProof(eml!); - - // const proof = await sdk.getProof("b80bc8ff-fb3e-4dbc-9ccb-b47a58b6faf6"); - - // console.log("proof done in browser: ", proof); - - console.log("Now verifying proof on blueprint: "); - const verified = await blueprint.verifyProof(proof, options); - - console.log("Proof verified an blueprint ", verified); - } catch (err) { - console.error("Failed to prove: ", err); - } - }); - } -} - -async function getEml() { - try { - const response = await fetch("/residency.eml"); // URL is relative to the root of the project - if (!response.ok) { - throw new Error("Network response was not ok " + response.statusText); - } - const data = await response.text(); // Get the content as text - return data; - } catch (error) { - console.error("There has been a problem with your fetch operation:", error); - } -} - -/* Remote -{ - "pi_a": [ - "17063359438686199848059549677080505582175973371540595163512962782152589527169", - "14748826498616296245994641796708403209064475072317766042674627316946003017489", - "1" - ], - "pi_b": [ - [ - "14348413057689360562398805801953275386049065240834882946282828494774191866218", - "12929470080078149739318799973573422983706676249600589816502713935921670226371" - ], - [ - "15830343317152098976197484682139574834084247828385375182889158022393927550541", - "17709520091615263615217118215804840639935165573520542298759031804979887650209" - ], - [ - "1", - "0" - ] - ], - "pi_c": [ - "18936002803358335702213624863956407854497826796385672079754635096249591869492", - "6766062450718229031166483621691960322279623114201212195467535443863379227927", - "1" - ], - "protocol": "groth16" - } - - - - [ - "17065011482015124977282970298439631182550457267344513671014250909064553612521", - "2334392307038315863", - "0", - "902461930945294469469049061864238462133168371753019686485682756284276", - "0", - "0" - ] - */ - -/*LOCAL -{ - "pi_a": [ - "3946109527236642940110893141288627183516254203777329904148768417522653916334", - "16198737390051261322724765804253323256226467174549524471445675626756427416426", - "1" - ], - "pi_b": [ - [ - "20047187957479147585944677059351059989110619525470592942347610940888280078707", - "3338707964462615616440109364623437104625296591775368283175213449152012141951" - ], - [ - "11689647619691931254513259870491678813922474804575712935358256625739832521580", - "16301929682796746758998192804467981570023141091760727529177043786858155055983" - ], - [ - "1", - "0" - ] - ], - "pi_c": [ - "18196242004022942351417351882217404140873162679256310930511286701459954183599", - "17952721507600032945668554149457354856619683782816798249431089159479173044418", - "1" - ], - "protocol": "groth16", - "curve": "bn128" -} - -[ - "17065011482015124977282970298439631182550457267344513671014250909064553612521", - "2334392307038315863", - "0", - "902461930945294469469049061864238462133168371753019686485682756284276", - "0", - "0" -] - -*/ +// import zkeSdk, { GenerateProofOptions } from "../../src"; +// import { initNoirWasm } from "@zk-email/sdk/initNoirWasm"; + +// export function setupNoirProver(element: HTMLElement) { +// const sdk = zkeSdk({ baseUrl: "http://127.0.0.1:8080" }); +// // const sdk = zkeSdk({ baseUrl: "https://dev-conductor.zk.email" }); + +// const proveButton = element.querySelector("button"); +// if (proveButton) { +// proveButton.addEventListener("click", async () => { +// try { +// console.log("getting blueprint"); +// // const blueprint = await sdk.getBlueprintById("008b5da5-fbda-4445-b7df-6b0c6dde4bb1"); +// const blueprint = await sdk.getBlueprintById("58a1b5c0-6633-4eb0-9fa8-9e5d605069ab"); + +// console.log("blueprint: ", blueprint); + +// const prover = blueprint.createProver({ isLocal: true }); +// console.log("prover"); +// console.log("typeof prover", typeof prover); + +// const eml = await getEml(); + +// const isValidEml = await blueprint.validateEmail(eml!); + +// console.log("isValidEml: ", isValidEml); + +// // console.log("putting in eml: ", eml); +// const externalInputs = { +// name: "name", +// value: "master", +// maxLength: 32, +// }; +// const noirWasm = await initNoirWasm(); +// const options: GenerateProofOptions = { noirWasm }; +// console.log("got the options: ", options); + +// const proof = await prover.generateProof(eml!, [externalInputs], options); +// console.log("got the noir proof: ", proof); + +// // const proof = await prover.generateProof(eml!); + +// // const proof = await sdk.getProof("b80bc8ff-fb3e-4dbc-9ccb-b47a58b6faf6"); + +// // console.log("proof done in browser: ", proof); + +// console.log("Now verifying proof on blueprint: "); +// const verified = await blueprint.verifyProof(proof, options); + +// console.log("Proof verified an blueprint ", verified); +// } catch (err) { +// console.error("Failed to prove: ", err); +// } +// }); +// } +// } + +// async function getEml() { +// try { +// const response = await fetch("/residency.eml"); // URL is relative to the root of the project +// if (!response.ok) { +// throw new Error("Network response was not ok " + response.statusText); +// } +// const data = await response.text(); // Get the content as text +// return data; +// } catch (error) { +// console.error("There has been a problem with your fetch operation:", error); +// } +// } + +// /* Remote +// { +// "pi_a": [ +// "17063359438686199848059549677080505582175973371540595163512962782152589527169", +// "14748826498616296245994641796708403209064475072317766042674627316946003017489", +// "1" +// ], +// "pi_b": [ +// [ +// "14348413057689360562398805801953275386049065240834882946282828494774191866218", +// "12929470080078149739318799973573422983706676249600589816502713935921670226371" +// ], +// [ +// "15830343317152098976197484682139574834084247828385375182889158022393927550541", +// "17709520091615263615217118215804840639935165573520542298759031804979887650209" +// ], +// [ +// "1", +// "0" +// ] +// ], +// "pi_c": [ +// "18936002803358335702213624863956407854497826796385672079754635096249591869492", +// "6766062450718229031166483621691960322279623114201212195467535443863379227927", +// "1" +// ], +// "protocol": "groth16" +// } + + + +// [ +// "17065011482015124977282970298439631182550457267344513671014250909064553612521", +// "2334392307038315863", +// "0", +// "902461930945294469469049061864238462133168371753019686485682756284276", +// "0", +// "0" +// ] +// */ + +// /*LOCAL +// { +// "pi_a": [ +// "3946109527236642940110893141288627183516254203777329904148768417522653916334", +// "16198737390051261322724765804253323256226467174549524471445675626756427416426", +// "1" +// ], +// "pi_b": [ +// [ +// "20047187957479147585944677059351059989110619525470592942347610940888280078707", +// "3338707964462615616440109364623437104625296591775368283175213449152012141951" +// ], +// [ +// "11689647619691931254513259870491678813922474804575712935358256625739832521580", +// "16301929682796746758998192804467981570023141091760727529177043786858155055983" +// ], +// [ +// "1", +// "0" +// ] +// ], +// "pi_c": [ +// "18196242004022942351417351882217404140873162679256310930511286701459954183599", +// "17952721507600032945668554149457354856619683782816798249431089159479173044418", +// "1" +// ], +// "protocol": "groth16", +// "curve": "bn128" +// } + +// [ +// "17065011482015124977282970298439631182550457267344513671014250909064553612521", +// "2334392307038315863", +// "0", +// "902461930945294469469049061864238462133168371753019686485682756284276", +// "0", +// "0" +// ] + +// */ diff --git a/src/login_for_email/microsoft.ts b/src/login_for_email/microsoft.ts index 1fc5147..7f6b87f 100644 --- a/src/login_for_email/microsoft.ts +++ b/src/login_for_email/microsoft.ts @@ -93,6 +93,7 @@ export interface OutlookEmailResponse { subject: string; receivedDateTime: string; internetMessageId: string; + internetMessageHeaders: { name: string; value: string }[]; body: { content: string; contentType: string; @@ -308,38 +309,77 @@ export class Outlook implements EmailProvider { `Date: ${email.receivedDateTime}`, `Subject: ${email.subject || "No Subject"}`, "MIME-Version: 1.0", + `From: ${email.internetMessageHeaders?.find((header) => header.name === "From")?.value}`, `Content-Type: ${email.body.contentType}; charset=UTF-8`, + `DKIM-Signature: ${email.internetMessageHeaders?.find((header) => header.name === "DKIM-Signature")?.value}`, "", ].join("\r\n"); return headers + "\r\n" + email.body.content; } + private createRawValidEmail(email: RawOutlookEmailResponse): string { + console.log("email: ", email); + const dkimHeaderLine = + "DKIM-Signature: " + + email.internetMessageHeaders?.find((header) => header.name === "DKIM-Signature")?.value; + + // Split the decodedContents into headers and body + // The first occurrence of "\r\n\r\n" separates headers from body. + const parts = email.body.content.split("\r\n\r\n", 2); // Split at most twice + const headersPart = parts[0]; + const bodyPart = parts[1] || ""; // In case there's no body, though unlikely for an email + + // Insert the DKIM-Signature line into the headers. + // Find the Content-Type header and insert after it. + const headerLines = headersPart.split("\r\n"); + let newHeaderLines = []; + let inserted = false; + + for (const line of headerLines) { + newHeaderLines.push(line); + if (line.toLowerCase().startsWith("content-type:")) { + newHeaderLines.push(dkimHeaderLine); + inserted = true; + } + } + + // If for some reason Content-Type wasn't found, insert it before the last blank line. + // This fallback should rarely be hit with valid email data. + if (!inserted) { + console.warn( + "Content-Type header not found. Inserting DKIM-Signature before the body separator." + ); + // Reconstruct without the newHeaderLines logic, just append before body + const fullEmlContent = headersPart + "\r\n" + dkimHeaderLine + "\r\n\r\n" + bodyPart; + return fullEmlContent; + } else { + const fullEmlContent = newHeaderLines.join("\r\n") + "\r\n\r\n" + bodyPart; + return fullEmlContent; + } + } + // Get a specific email by ID in its raw format - async fetchEmailRawById(accessToken: string, emailId: string): Promise { - const url = `https://graph.microsoft.com/v1.0/me/messages/${emailId}?$select=id,subject,receivedDateTime,internetMessageId,body`; + async fetchEmailRawById(emailId: string): Promise { + const accessToken = await this.loginWithMicrosoft.getAccessToken(); + + const url = `https://graph.microsoft.com/v1.0/me/messages/${emailId}/$value`; const response = await fetch(url, { headers: { Authorization: `Bearer ${accessToken}`, - "Content-Type": "application/json", }, }); if (response.ok) { - const email: OutlookEmailResponse = await response.json(); - - // Convert to raw format - let rawContent = email.body.content; - if (email.body.contentType === "html") { - rawContent = this.constructRawEmail(email); - } + const rawEmail = await response.text(); + const subject = rawEmail.match(/Subject: (.*)/)?.[1] || "No Subject"; return { - emailMessageId: email.id, - subject: email.subject || "No Subject", - internalDate: email.receivedDateTime, - decodedContents: rawContent, + decodedContents: rawEmail, + emailMessageId: emailId, + subject, + internalDate: rawEmail.match(/Date: (.*)/)?.[1] || new Date().toISOString(), }; } else { console.error(`Failed to fetch email with ID: ${emailId}`, response);