Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SPF parsing and IP evaluation #203

Merged
merged 5 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
132 changes: 132 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@
"dependencies": {
"abortcontroller-polyfill": "^1.7.5",
"babel-polyfill": "^6.26.0",
"cidr-matcher": "^2.1.1",
"do-bulma": "github:do-community/do-bulma",
"do-vue": "github:do-community/do-vue",
"vue": "^3.3.4",
"vue-tippy": "^6.2.0",
"web-whois": "0.0.6"
},
"devDependencies": {
"@types/cidr-matcher": "^2.1.2",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"@vue/component-compiler-utils": "^3.3.0",
Expand Down
65 changes: 28 additions & 37 deletions src/spf-explainer/templates/app.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
Copyright 2022 DigitalOcean
Copyright 2024 DigitalOcean

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -46,7 +46,7 @@ limitations under the License.
<EvalNotif ref="EvalNotif" :ip="ipEval"></EvalNotif>
</template>
<template #buttons>
<form v-if="!SPFSandbox.empty()" autocomplete="on" @submit.prevent="">
<form v-if="showEvalForm" autocomplete="on" @submit.prevent="">
<div class="input-container">
<label for="EvaluateInput" class="hidden">Evaluate</label>
<input
Expand Down Expand Up @@ -87,11 +87,11 @@ limitations under the License.

<script>
import i18n from "../i18n"
import cfDNS from "../../shared/utils/cfDNS"
import SPFBase from "./spf_base"
import { spawnLine } from "../utils/line_spawn"
import NoSPFRecords from "./no_spf_records"
import SPFSandbox from "../utils/spf_sandbox"
import getSPFRecords from "../utils/spf_records"
import EvalNotif from "./eval_notif"
import AllPartExplanations from "./all_part_explanations"
import ErrorModal from "../../shared/templates/error_modal"
Expand Down Expand Up @@ -130,6 +130,7 @@ limitations under the License.
loading: false,
records: [],
ipEval: "",
showEvalForm: false,
errorMessage: "",
spfTop,
spfBottom,
Expand All @@ -156,44 +157,28 @@ limitations under the License.
this.$data.errorMessage = `<p>${message}</p>`
this.$refs.ErrorModal.open()
},
async cfPart(input) {
async lookup(input) {
const [domain, result] = await validateDomain(input)
if (result !== null) return this.error(result)

const res = await cfDNS(domain, "TXT")
if (!res.ok) return this.error(i18n.templates.app.fetchError)
let json
try {
json = await res.json()
} catch {
// Sometimes Cloudflare's DNS sends invalid JSON in the event that it is invalid.
// That has happened here.
return this.error(i18n.templates.app.fetchError)
if (result !== null) {
this.error(result)
return
}

if (!json.Answer) {
this.$refs.NoSPFRecords.toggle()
return false
}
SPFSandbox.wipe()
SPFSandbox.listen(() => this.$data.showEvalForm = !SPFSandbox.empty())
remakeController()

return json
},
async lookup(domain, json) {
if (this.$data.lastDomain === domain) this.$data.records = []
this.$data.records = await getSPFRecords(domain)
window.history.pushState({}, "", `?domain=${domain}`)

const records = []
for (const answer of json.Answer) {
answer.data = answer.data.substr(1).slice(0, -1)
if (answer.data.startsWith("v=spf1")) records.push(answer)
}
if (records.length === 0) {
return this.$refs.NoSPFRecords.toggle()
if (this.$data.records.length === 0) {
this.$refs.NoSPFRecords.open()
return
} else {
this.$refs.NoSPFRecords.close()
}

this.$data.records = records
window.history.pushState({}, "", `?domain=${domain}`)
SPFSandbox.wipe()
remakeController()
this.$data.firstSearch = false
this.$data.lastDomain = domain
},
Expand All @@ -202,12 +187,18 @@ limitations under the License.

try {
el.classList.add("is-loading")
const domain = this.$data.domain.toLowerCase().replace(/^https*:\/\//, "").replace(/\/+$/, "")
const j = await this.cfPart(domain)
if (!j) return
this.$data.loading = true

try {
const domain = this.$data.domain.toLowerCase().replace(/^https*:\/\//, "").replace(/\/+$/, "")
await this.lookup(domain)
} catch {
// Sometimes Cloudflare's DNS sends invalid JSON in the event that it is invalid.
this.error(i18n.templates.app.fetchError)
return
}

spawnLine(undefined)
await this.lookup(domain, j)
} catch(e) {
console.error(e)
} finally {
Expand Down
Loading