Skip to content

turnstile #2749

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
119 changes: 60 additions & 59 deletions cmd/explorer/main.go

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions handlers/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"math"
"net/http"
"time"
)

// Index will return the main "index" page using a go template
Expand Down Expand Up @@ -112,3 +113,38 @@ func calculateChurn(page *types.IndexPageData) {
page.ValidatorsPerEpoch = *limit
page.ValidatorsPerDay = limit_per_day
}

func VerifyTurnstile(w http.ResponseWriter, r *http.Request) {

if utils.Config.Frontend.Turnstile.Enabled {

err := utils.VerifyTurnstileToken(r)

cookie := http.Cookie{
Name: "turnstile",
Value: "verified",
Path: "/",
MaxAge: int(utils.Config.Frontend.Turnstile.CookieMaxAge),
HttpOnly: false,
Secure: true,
SameSite: http.SameSiteLaxMode,
}

if err != nil {
fmt.Println(err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use utils.LogError

// clear cookie
cookie.MaxAge = -1
http.SetCookie(w, &cookie)
http.Error(w, "Turnstile challenge failed", http.StatusServiceUnavailable)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on the error you might want to return a different status code. For example if the challenge was not successful, you return a specific error but returning service unavailable is not correct, something like Bad Request would be better suited.

return
}

validuntil := time.Now().Add(time.Duration(utils.Config.Frontend.Turnstile.SessionMaxAge) * time.Second).Format(time.RFC3339)

utils.SessionStore.SCS.Put(r.Context(), "TURNSTILE::VALIDUNTIL", validuntil)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Store current timestamp in SessionStore and in the verify function check if timestamp + SessionMaxAge > now. That way we can adjust the window how long it is valid whenever we want or a some point even dynamically based on the load.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not store and retrieve it as an int64, no need to format it

http.SetCookie(w, &cookie)
w.Write([]byte("Success"))
} else {
w.Write([]byte("Turnstile not enabled"))
}
}
1 change: 1 addition & 0 deletions handlers/pageData.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func InitPageData(w http.ResponseWriter, r *http.Request, active, path, title st
MainMenuItems: createMenuItems(active, isMainnet),
TermsOfServiceUrl: utils.Config.Frontend.Legal.TermsOfServiceUrl,
PrivacyPolicyUrl: utils.Config.Frontend.Legal.PrivacyPolicyUrl,
TurnstileSiteKey: utils.Config.Frontend.Turnstile.SiteKey,
}

adConfigurations, err := db.GetAdConfigurationsForTemplate(mainTemplates, data.NoAds)
Expand Down
170 changes: 86 additions & 84 deletions static/js/banner.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,101 +28,103 @@ function getCookie(cname) {
}

function updateBanner() {
fetch("/latestState")
.then(function (res) {
return res.json()
})
.then(function (data) {
// always visible
var epochHandle = document.getElementById("banner-epoch-data")
waitForTurnstileToken(() => {
fetch("/latestState", { headers: { "X-TURNSTILE-TOKEN": window.turnstileToken } })
.then(function (res) {
return res.json()
})
.then(function (data) {
// always visible
var epochHandle = document.getElementById("banner-epoch-data")

if (data.currentEpoch) {
epochHandle.innerHTML = addCommas(data.currentEpoch)
epochHandle.setAttribute("href", "/epoch/" + data.currentEpoch)
}
if (data.currentEpoch) {
epochHandle.innerHTML = addCommas(data.currentEpoch)
epochHandle.setAttribute("href", "/epoch/" + data.currentEpoch)
}

var slotHandle = document.getElementById("banner-slot-data")
if (data.currentSlot) {
slotHandle.innerHTML = addCommas(data.currentSlot)
slotHandle.setAttribute("href", "/slot/" + data.currentSlot)
}
var slotHandle = document.getElementById("banner-slot-data")
if (data.currentSlot) {
slotHandle.innerHTML = addCommas(data.currentSlot)
slotHandle.setAttribute("href", "/slot/" + data.currentSlot)
}

var ethPriceHandle = document.getElementById("banner-eth-price-data")
var ethPriceHandle = document.getElementById("banner-eth-price-data")

try {
let userCurrency = getCookie("currency")
if (userCurrency == data.rates.mainCurrency) userCurrency = data.rates.tickerCurrency
var price = data.rates.mainCurrencyPrices[userCurrency]
ethPriceHandle.innerHTML = `<span class='currency-symbol'>${price.symbol} </span><span class='k-formatted-price'>${price.truncPrice}</span><span class='price'>${addCommas(price.roundPrice)}</span>`
} catch (err) {
console.error("failed updating banner-price:", err)
}
try {
let userCurrency = getCookie("currency")
if (userCurrency == data.rates.mainCurrency) userCurrency = data.rates.tickerCurrency
var price = data.rates.mainCurrencyPrices[userCurrency]
ethPriceHandle.innerHTML = `<span class='currency-symbol'>${price.symbol} </span><span class='k-formatted-price'>${price.truncPrice}</span><span class='price'>${addCommas(price.roundPrice)}</span>`
} catch (err) {
console.error("failed updating banner-price:", err)
}

var finDelayDataHandle = document.getElementById("banner-fin-data")
finDelayHtml = `
<div id="banner-fin" class="info-item d-flex mr-3">
<div class="info-item-header mr-1 text-warning">
<span class="item-icon">
<i class="fas fa-exclamation-triangle" data-toggle="tooltip" title="" data-original-title="The last finalized epoch was ${data.finalityDelay} epochs ago."></i>
</span>
<span class="item-text">
Finality
</span>
var finDelayDataHandle = document.getElementById("banner-fin-data")
finDelayHtml = `
<div id="banner-fin" class="info-item d-flex mr-3">
<div class="info-item-header mr-1 text-warning">
<span class="item-icon">
<i class="fas fa-exclamation-triangle" data-toggle="tooltip" title="" data-original-title="The last finalized epoch was ${data.finalityDelay} epochs ago."></i>
</span>
<span class="item-text">
Finality
</span>
</div>
<div class="info-item-body text-warning">
<span id="banner-fin-data">${data.finalityDelay}</span>
<i class="fas fa-exclamation-triangle item-text" data-toggle="tooltip" title="" data-original-title="The last finalized epoch was ${data.finalityDelay} epochs ago."></i>
</div>
</div>
<div class="info-item-body text-warning">
<span id="banner-fin-data">${data.finalityDelay}</span>
<i class="fas fa-exclamation-triangle item-text" data-toggle="tooltip" title="" data-original-title="The last finalized epoch was ${data.finalityDelay} epochs ago."></i>
</div>
</div>
`
`

if (!finDelayDataHandle && data.finalityDelay > 3 && !data.syncing) {
// create fin delay node
document.getElementById("banner-slot").insertAdjacentHTML("afterend", finDelayHtml)
$("#banner-fin i").each(function () {
$(this).tooltip("update")
})
} else if (finDelayDataHandle && data.finalityDelay > 3 && !data.syncing) {
// update fin delay node
finDelayDataHandle.textContent = data.finalityDelay
var icons = document.querySelectorAll("#banner-fin i")
for (let i = 0; i < icons.length; i++) {
const icon = icons[i]
icon.setAttribute("data-original-title", `The last finalized epoch was ${data.finalityDelay} epochs ago.`)
if (!finDelayDataHandle && data.finalityDelay > 3 && !data.syncing) {
// create fin delay node
document.getElementById("banner-slot").insertAdjacentHTML("afterend", finDelayHtml)
$("#banner-fin i").each(function () {
$(this).tooltip("update")
})
} else if (finDelayDataHandle && data.finalityDelay > 3 && !data.syncing) {
// update fin delay node
finDelayDataHandle.textContent = data.finalityDelay
var icons = document.querySelectorAll("#banner-fin i")
for (let i = 0; i < icons.length; i++) {
const icon = icons[i]
icon.setAttribute("data-original-title", `The last finalized epoch was ${data.finalityDelay} epochs ago.`)
}
$("#banner-fin i").each(function () {
$(this).tooltip("update")
})
} else {
// delete fin delay node if it exists
let findDelayHandle = document.getElementById("banner-fin")
if (findDelayHandle) findDelayHandle.remove()
}
$("#banner-fin i").each(function () {
$(this).tooltip("update")
})
} else {
// delete fin delay node if it exists
let findDelayHandle = document.getElementById("banner-fin")
if (findDelayHandle) findDelayHandle.remove()
}
if (data.syncing) {
// remove fin delay if we are still syncing
let findDelayHandle = document.getElementById("banner-fin")
if (findDelayHandle) findDelayHandle.remove()
if (data.syncing) {
// remove fin delay if we are still syncing
let findDelayHandle = document.getElementById("banner-fin")
if (findDelayHandle) findDelayHandle.remove()

var bannerHandle = document.getElementById("banner-status")
if (!bannerHandle) {
var statusHtml = `
<a data-toggle="tooltip" title="The explorer is currently syncing with the network" id="banner-status" style="white-space: nowrap;" class="mr-2" href="/"><i class="fas fa-sync"></i> <span>|</span></a>
var bannerHandle = document.getElementById("banner-status")
if (!bannerHandle) {
var statusHtml = `
<a data-toggle="tooltip" title="The explorer is currently syncing with the network" id="banner-status" style="white-space: nowrap;" class="mr-2" href="/"><i class="fas fa-sync"></i> <span>|</span></a>
`
document.getElementById("banner-home").remove()
document.getElementById("banner-stats").insertAdjacentHTML("afterbegin", statusHtml)
}
} else {
// delete sync if it exists otherwise do nothing
var statusHandle = document.getElementById("banner-status")
if (statusHandle) {
var homeHtml = `
<a id="banner-home" style="white-space: nowrap;" class="mr-2" href="/"><i class="fas fa-home"></i> <span>|</span></a>
`
document.getElementById("banner-home").remove()
document.getElementById("banner-stats").insertAdjacentHTML("afterbegin", statusHtml)
}
} else {
// delete sync if it exists otherwise do nothing
var statusHandle = document.getElementById("banner-status")
if (statusHandle) {
var homeHtml = `
<a id="banner-home" style="white-space: nowrap;" class="mr-2" href="/"><i class="fas fa-home"></i> <span>|</span></a>
`
statusHandle.remove()
document.getElementById("banner-stats").insertAdjacentHTML("afterbegin", homeHtml)
statusHandle.remove()
document.getElementById("banner-stats").insertAdjacentHTML("afterbegin", homeHtml)
}
}
}
})
})
})
}

// update the banner every 12 seconds
Expand Down
Loading