-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #59 from zkemail/feat/sample-email
feat: added sample email flow when creating patterns
- Loading branch information
Showing
9 changed files
with
607 additions
and
353 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 11 additions & 13 deletions
24
packages/app/src/app/api/script/circuit_input/[[...slug]]/route.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,21 @@ | ||
import { NextRequest, NextResponse } from "next/server"; | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import { getEntryBySlug } from "@/lib/models/entry"; | ||
|
||
const OUTPUT_DIR = process.env.GENERATED_OUTPUT_DIR || "./output"; | ||
|
||
export async function GET(request: NextRequest, { params }: { params: { slug: string[] }}) { | ||
const slug = params.slug.join('/') | ||
const entry = await getEntryBySlug(slug); | ||
if (!entry) { | ||
return new NextResponse("Entry not found", { status: 404 }) | ||
try { | ||
const file = fs.readFileSync(path.join(OUTPUT_DIR, "code", slug, "generate_inputs_worker_bundled.js")) | ||
const content = Buffer.from(file); | ||
return new NextResponse(content, { | ||
headers: { | ||
'Content-Type': 'text/javascript', | ||
"Content-Length": '' + content.length, | ||
} | ||
}) | ||
} catch (e) { | ||
return new NextResponse("Not found", { status: 404 }) | ||
} | ||
const file = fs.readFileSync(path.join(OUTPUT_DIR, "code", entry?.slug, "generate_inputs_worker_bundled.js")) | ||
const content = Buffer.from(file); | ||
|
||
return new NextResponse(content, { | ||
headers: { | ||
'Content-Type': 'text/javascript', | ||
"Content-Length": ''+content.length, | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
import { getEntryBySlug } from "@/lib/models/entry"; | ||
import Content from "./content"; | ||
|
||
export default async function EditPage({params}: {params: {slug: string[]}}) { | ||
export default async function EditPage({params, searchParams: {sampleEmail}}: {params: {slug: string[]}, searchParams: {sampleEmail: string}}) { | ||
const slug = params.slug.join('/'); | ||
const entry = await getEntryBySlug(slug); | ||
|
||
if (!entry) { | ||
return (<h1>Entry not found</h1>) | ||
} | ||
return (<Content entry={entry}/>) | ||
return (<Content entry={entry} sampleEmail={sampleEmail} />) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
'use server'; | ||
import { z } from 'zod'; | ||
import { formSchema } from '../form'; | ||
import { generateCodeLibrary } from '@/lib/code-gen/gen'; | ||
import { verifyDKIMSignature } from "@zk-email/helpers/dist/dkim"; | ||
|
||
export interface ProcessEmailResult { | ||
error: boolean, | ||
message: string, | ||
parameters?: { | ||
maxHeaderLength: number, | ||
maxBodyLength?: number, | ||
domain: string, | ||
selector: string, | ||
}, | ||
matches: { | ||
name: string, | ||
match: string, | ||
}[], | ||
} | ||
|
||
export async function processEmail(values: z.infer<typeof formSchema>, email: string): Promise<ProcessEmailResult> { | ||
let res; | ||
let result; | ||
let bodyString; | ||
let headerString; | ||
|
||
try { | ||
result = await verifyDKIMSignature(email) | ||
} catch (e: any) { | ||
return { | ||
error: true, | ||
matches: [], | ||
message: "Error verifying DKIM signature: " + e.toString() | ||
} | ||
} | ||
headerString = result.headers.toString(); | ||
const headerLength = result.headers.length; | ||
const maxHeaderLength = Math.ceil(headerLength / 64) * 64; | ||
const domain = result.signingDomain; | ||
const selector = result.selector; | ||
res = { | ||
maxHeaderLength, | ||
domain, | ||
selector, | ||
} | ||
if (!values.parameters.ignoreBodyHashCheck) { | ||
bodyString = result.body.toString(); | ||
if (values.parameters.shaPrecomputeSelector) { | ||
const split = bodyString.split(values.parameters.shaPrecomputeSelector); | ||
if (split.length > 2) { | ||
return { | ||
error: true, | ||
matches: [], | ||
message: "Non-unique email body cut-off value. Use something that can split the email into strictly two parts." | ||
} | ||
} | ||
if (split.length == 1) { | ||
return { | ||
error: true, | ||
matches: [], | ||
message: "Email body cut-off value is not found in the email body." | ||
} | ||
} | ||
const bodyLength = split[1].length; | ||
const maxBodyLength = Math.ceil(bodyLength / 64) * 64; | ||
res = { | ||
...res, | ||
maxBodyLength, | ||
} | ||
} | ||
} | ||
|
||
// Apply regex | ||
const regexes = values.parameters.values.map((v: any) => { | ||
let publicGroups: number[] = []; | ||
let index = 1; | ||
const regex = v.parts.reduce((acc: any, part: any) => { | ||
if (part.is_public) { | ||
publicGroups.push(index); | ||
index++; | ||
return acc + "(" + part.regex_def + ")" | ||
} | ||
return acc + part.regex_def | ||
}, ""); | ||
return { | ||
regex, | ||
publicGroups, | ||
name: v.name, | ||
location: v.location, | ||
} | ||
}) | ||
|
||
let matches = [] | ||
|
||
for (const regex of regexes) { | ||
if (regex.location == "body" && bodyString) { | ||
const match = bodyString.match(regex.regex) | ||
if (match) { | ||
for (const group of regex.publicGroups) { | ||
matches.push({ | ||
name: regex.name, | ||
match: match[group], | ||
}) | ||
} | ||
} | ||
} else { | ||
const match = headerString.match(regex.regex) | ||
if (match) { | ||
for (const group of regex.publicGroups) { | ||
matches.push({ | ||
name: regex.name, | ||
match: match[group], | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
|
||
const parameters = { | ||
...values.parameters, | ||
version: values.useNewSdk ? "v2" : "v1", | ||
} | ||
try { | ||
await generateCodeLibrary(parameters, "drafts/" + values.slug, "DRAFT"); | ||
} catch (e: any) { | ||
return { | ||
error: true, | ||
matches: [], | ||
message: "Error generating code: " + e.toString() | ||
} | ||
} | ||
return { | ||
error: false, | ||
message: "Email processed successfully", | ||
parameters: res, | ||
matches, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.