Instantly share code, notes, and snippets.
ColdFusion SetCookie UDF to add support for samesite
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
<!--- 9/15/2010 Original: http://www.modernsignal.com/coldfusionhttponlycookie | |
<cfset SetCookie(name="logintoken", value="sometoken", secure=true, httponly=true, samesite="strict")> | |
11/1/2019 Updated to add support for encodevalue, preserveCase & samesite | |
https://gamesover2600.tumblr.com/post/188744661844/coldfusion-setcookie-udf-supports-samesite | |
Results in double cookie headers being added to HTTP response, but 2nd cookie header overwrites 1st cookie header | |
and variable is properly added to CF cookie scope. | |
WARNING: If any content is flushed, headers can't be added & error is thrown (I have workaround, but it's specific to ACF) ---> | |
<cffunction name="SetCookie" hint="Replacement for cfcookie that handles httponly and samesite cookies" output="no" returntype="void"> | |
<cfargument name="name" type="string" required="true"> | |
<cfargument name="value" type="string" required="true"> | |
<cfargument name="expires" type="any" default="" hint="''=session only|now|never|[date]|[number of days]"> | |
<cfargument name="secure" type="boolean" default="false"> | |
<cfargument name="path" type="string" default="/"> | |
<cfargument name="domain" type="string" default=""> | |
<cfargument name="httponly" type="boolean" default="false"> | |
<cfargument name="encodevalue" type="boolean" default="true"> | |
<cfargument name="preserveCase" type="boolean" default="false"> | |
<cfargument name="samesite" type="string" default=""><!--- None, Strict, Lax ---> | |
<cfset var cookieData = []> | |
<cfset var expDate = ""> | |
<cfif isValid("boolean", Arguments.PreserveCase) AND Arguments.PreserveCase> | |
<!--- nothing ---> | |
<cfelse> | |
<cfset Arguments.Name = UCase(Arguments.Name)> | |
</cfif> | |
<cfif isvalid("boolean", arguments.encodeValue) AND arguments.encodevalue> | |
<cfset arrayAppend(cookieData, "#Arguments.name#=#URLEncodedFormat(arguments.value)#")> | |
<cfelse> | |
<cfset arrayAppend(cookieData, "#Arguments.name#=""#replace(argumments.value,'"','\"')#""")> | |
<cfset arrayAppend(cookieData, "Version=1")> | |
</cfif> | |
<cfswitch expression="#Arguments.expires#"> | |
<cfcase value=""></cfcase> | |
<cfcase value="now"><cfset expDate = DateAdd("d",-1,Now())></cfcase> | |
<cfcase value="never"><cfset expDate = DateAdd("yyyy",30,Now())></cfcase> | |
<cfcase value="session"><cfset expDate = ""></cfcase> | |
<cfdefaultcase> | |
<cfif IsDate(Arguments.expires)> | |
<cfset expDate = Arguments.expires> | |
<cfelseif IsNumeric(Arguments.expires)> | |
<cfset expDate = DateAdd("d",Arguments.expires,Now())> | |
</cfif> | |
</cfdefaultcase> | |
</cfswitch> | |
<cfif isValid("date", expDate)> | |
<cfset expDate = DateConvert("local2Utc",expDate)> | |
<cfset ArrayAppend(cookieData, "expires=#DateFormat(expDate, 'ddd, dd mmm yyyy')# #TimeFormat(expDate, 'HH:mm:ss')# -0000")> | |
</cfif> | |
<cfif Len(Arguments.domain)> | |
<cfset ArrayAppend(cookieData, "domain=#Arguments.domain#")> | |
</cfif> | |
<cfif Len(Arguments.path)> | |
<cfset ArrayAppend(cookieData, "path=#Arguments.path#")> | |
</cfif> | |
<cfif Arguments.secure> | |
<cfset ArrayAppend(cookieData, "SECURE")> | |
</cfif> | |
<cfif Arguments.httponly> | |
<cfset ArrayAppend(cookieData, "HttpOnly")> | |
</cfif> | |
<cfif ListFindNoCase("none,strict,lax", Arguments.samesite)> | |
<cfset ArrayAppend(cookieData, "SameSite=#Arguments.samesite#")> | |
</cfif> | |
<!--- generate cfcookie (using params that it allows) ---> | |
<cfif not len(arguments.expires)> | |
<cfset structDelete(arguments, "expires")> | |
</cfif> | |
<cfset structDelete(arguments, "samesite")> | |
<cfif isDefined("Server.ColdFusion.ProductVersion")> | |
<cfif Val(ListFirst(Server.ColdFusion.ProductVersion)) LT 9> | |
<cfset structDelete(arguments, "httponly")> | |
</cfif> | |
<cfif Val(ListFirst(Server.ColdFusion.ProductVersion)) LT 10> | |
<cfset structDelete(arguments, "encodevalue")> | |
<cfset structDelete(arguments, "preserveCase")> | |
</cfif> | |
</cfif> | |
<cfcookie attributecollection="#arguments#"> | |
<!--- follow it up with corrected cookie header ---> | |
<cfheader name="Set-Cookie" value="#ArrayToList(cookieData, '; ')#"> | |
</cffunction> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment