Last active
June 24, 2024 19:18
-
-
Save JamoCA/fd43c189379196b6a52884affea3ad51 to your computer and use it in GitHub Desktop.
ColdFusion UDF to temporarily cache data and return a UUID. Good for verifying form posts (ie, like CSRF) or building magic link passwordless logins for monolith web application.
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
<!--- tempCache UDF (2019-11-22) By SunStar Media | |
ColdFusion UDF to temporarily cache data and return a UUID. Used for verifying form posts (ie, like CSRF) or building magic | |
link passwordless logins for monolith web application. | |
GIST: https://gist.github.com/JamoCA/fd43c189379196b6a52884affea3ad51 | |
Twitter/X: https://x.com/gamesover/status/1803866104491839620 | |
Blog: https://dev.to/gamesover/tempcache-coldfusion-udf-32f9 | |
---> | |
<cfscript> | |
public any function tempCache( | |
any inputObject, | |
numeric minutes=5, | |
numeric maxMinutes=5, | |
boolean singleUse=false, | |
string cachePrefix="tempCache_" | |
) hint="Temporarily cache data for x minutes. (Pass object; returns UUID. Pass UUID, returns object.)" { | |
local.response = ""; | |
local.minutes = (val(arguments.minutes) gt 0) ? val(arguments.minutes) : 5; | |
local.maxMinutes = abs(val(arguments.maxMinutes)) + local.minutes; | |
if (issimplevalue(arguments.inputObject) && isvalid("UUID", arguments.inputObject)){ | |
local.response = cacheget("#arguments.cachePrefix##arguments.inputObject#"); | |
if (isnull(local.response)){ | |
local.response = {}; | |
} else if (arguments.singleUse){ | |
cacheremove("#arguments.cachePrefix##arguments.inputObject#"); | |
} | |
} else { | |
local.response = createuuid(); | |
cacheput("#arguments.cachePrefix##local.response#", arguments.inputObject, createtimespan(0, 0, local.maxMinutes, 0), createtimespan(0, 0, local.minutes, 0)); | |
} | |
return local.response; | |
} | |
</cfscript> | |
<cfparam name="url.Token" default=""> | |
<cfset tempConfig = [ | |
"inputObject": [ | |
"html": "<p>Hello World #datetimeformat(now(), "iso")#</p>", | |
"IPAddress": CGI.REMOTE_ADDR, | |
"timestamp": datetimeformat(now(), "iso") | |
], | |
"minutes": 5, | |
"maxMinutes": 5, | |
"singleUse": false | |
]> | |
<h2>tempCache Demo</h2> | |
<cfif len(url.Token)> | |
<fieldset> | |
<cfoutput> | |
<legend>Fetching "#url.Token#" from tempCache UDF</legend> | |
</cfoutput> | |
<cfif isvalid("UUID", url.Token)> | |
<cfset cacheResults = tempCache(url.Token)> | |
<cfif !structcount(cacheResults)> | |
<p style="color:red;"><b>No results.</b> Cache key doesn't exist</p> | |
<cfelseif !cacheResults.keyexists("IPAddress")> | |
<p style="color:red;"><b>Suspicious:</b> Cache key exists, but not IP address.</p> | |
<cfelseif cacheResults.IPAddress neq CGI.REMOTE_ADDR> | |
<p style="color:red;"><b>Suspicious:</b> IP address exists, but not same as current request.</p> | |
<cfelse> | |
<p style="color:green;"><b>Good:</b> IP address exists and is the same as current request.</p> | |
</cfif> | |
<cfoutput> | |
<p><b>Retry Token:</b> <a href="?Token=#url.Token#">#url.Token#</a></p> | |
</cfoutput> | |
<cfdump var="#cacheResults#" label="Cached data for #url.Token#"> | |
<cfelseif len(url.Token)> | |
<p style="color:green;"><b>Invalid:</b> ID is not a UUID</p> | |
</cfif> | |
</fieldset> | |
</cfif> | |
<cfset newToken = tempCache(argumentcollection=tempConfig)> | |
<cfoutput> | |
<fieldset> | |
<legend>New Token:</legend> | |
<p><a href="?Token=#newToken#">#newToken#</a></p> | |
<cfdump var="#tempConfig#" label="New ID Config (debugging)"> | |
</fieldset> | |
</cfoutput> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment