Visual Studio Code & Cold Fusion Markup (formatting) - coldfusion

For VSCode users unaware, Cold Fusion Markup is similar to HTML, XML, etc
<cfif variable is "value">
stuff
<cfelse>
other stuff
</cfif>
I've been using Visual Studio code as my preferred IDE, largely because I can make it feel like Visual Studio. It feels like a good hybrid between Brackets and Visual Studio.
Anyway.. there are two Extensions for CFML, and I've tried them both. They both seem functionally identical but neither one handles syntax formatting (both handle tag completion and syntax-coloring).
"*.cfm": "lang-cfml"
and
"*.cfm": "cfmhtml"
Being a tag-based language, I could leave it on default but the default formatter does not handle SQL well at all.
I can get by without auto-formatting but it sure is a nice feature. I tried this with the default formatter and the SQL is still reformatted to a fashion as shown below, and I lose tag completion.
"html.format.unformatted": "cfquery, a, [...] textarea, tt, var" (in settings.json.
<cfquery...>
select field from table where username =
<cfqueryparam ...value="#form.username#" /> and password =
<cfqueryparam ...value="#encryptedpassword#" />
</cfquery>
which is quite frustrating to read.
Is there anything I can do besides learning to alter the extensions and seeing if I can improve it?

Related

Adding page numbers to PDF with Lucee cfpdf

Everything I have found about CFPDF says that the way to add page numbers to a PDF is like this
<cfpdf action="addFooter" source="#finalFile#" name="mypdf"
text="Page _PAGENUMBER of _LASTPAGENUMBER" />
The problem is every reference I have found is for coldFusion 9 and before and I am wondering if maybe the Lucee guys didn't include this functionality because I get an error that says
Attribute text is not allowed for tag cfpdf
Is this a syntax issue or an oversight by Lucee/Railo not to put this in.
I am merging a group of PDFs using CFPDFs merge feature that this is working correctly but I now need to put page numbers on the PDF and that is were I am hitting a wall.
Here is the a more complete picture of what I am trying to do. The only part that isn't working is the addFooter line
<cfpdf action = "merge" destination="#finalFile#" overwrite="yes">
<cfloop array="#arrayOfPdfs#" index="k">
<cfpdfparam source="#k#">
</cfloop>
</cfpdf>
<cfpdf action="addFooter" source="#finalFile#" name="mypdf"
text="Page _PAGENUMBER of _LASTPAGENUMBER" />
<cfloop array="#arrayOfPdfs#" index="k">
<cffile action="delete" file="#k#">
</cfloop>
I did a little searching and here is what I found. Remember that Lucee was previously Railo. I found your exact issue reported as a bug in Railo back in August 2011 - cfpdf addfooter not supported It looks like that bug was never addressed.
The Lucee docs mention the ability to add a header/footer using cfpdf in the lead-in paragraph but not in the tags attributes - Lucee documentation for cfpdf
Create PDF portfolios - Add and remove header/footer from PDF documents - Optimize PDF documents
(my emphasis) But there is no mention of addheader or addfooter beyond that.
This just mirrors the original Railo documentation - Railo documentation for cfpdf
I am guessing that this bug was never resolved and now exists (still exists) in Lucee. I would create a new issue for the Lucee group to revisit this - https://luceeserver.atlassian.net/secure/Dashboard.jspa
It is interesting that it seems to accept the addfooter action just not the text attribute. That makes it seem like a bug.
UPDATE 11/18/2021
From Andy's comment below "It looks like a fix is coming from the PULL requests at github.com/lucee/extension-pdf/pulls specifically github.com/lucee/extension-pdf/pull/31" it appears that a fix may finally be coming for this issue. Thanks for the update Andy!

How do I locate a custom tag instantiation in a coldFusion App

I am migrating a very old app (currently running in CF8) to Lucee. But I am running into a problem with what appears to be a custom tag of some sort.
I have tried to make sure that all the virtual directories are the same in IIS for both the old and the new installs. And made sure the mapping and custom tag paths in both the CFIDE and the Lucee Admin are the same.
But I am getting this error. And can't figure out how this cflink is being instantiated.
I have found the location of the erroring code on line 300 the utils.cfc file
I haven't used custom tags in a long time but thought they were generally called with an underscore and the code should like more like <cf_link pageid="#LinkPageID#" Init="start"> if this was being called as a custom tag.
If I go the the current CF server that is running this app I can find that a cfclass files HAS been created
From a file called cflink.cfm in a directory called "tags" even though there seems to be no mapping for the "tags" directory nor is is listed under "custom tags paths" in the administrator.
This App was start in 2003 and as you can imagine has grown into a mis-match of spaghetti code and no one from the beginning is around to ask how this tag is instantiated.
Does anyone with experience in legacy code has any other ideas where I should be looking to try to get this to work? The currently has only a production environment and if I can get it to work on Lucee it will not only be a dev environment that hasn't existed here in 10 years but will be a great way for me to be able to continue showcasing Lucee as a great CFML engine
Adding addition info
Leigh had asked if the init might be a jar reference but in the cflink.cfm file I see this code:
<cfif Attributes.Init IS "start">
<cfset Request.PageID = Attributes.PageID>
<cfset Request.Page_Width = Variables.qParentInfo.Page_Width>
<cfset Request.Page_Height = Variables.qParentInfo.Page_Height>
<cfset Request.Page_TypeID = Variables.qParentInfo.Page_TypeID>
<cfset Request.AddPath = "">
<cfif IsDefined("Attributes.Anchor")>
<cfset Request.Anchor = Attributes.Anchor>
<cfelse>
<cfset Request.Anchor = "">
</cfif>
<cfset Request.IsInternalLink = false>
<cfexit method="EXITTAG">
</cfif>
There are also references to cflink in the code inside tags\cflink.cfm
<cfif Len(Variables.qParentInfo.ParentID) GT 0>
<!--- Add the page title to the end of the path --->
<cfset Request.AddPath = ReplaceNoCase(Variables.qParentInfo.Nav_Title," ","_","ALL") & "/" & Request.AddPath>
<cflink init="working" pageid="#Variables.qParentInfo.ParentID#" popcode="#Attributes.popcode#">
<cfelse> ......</cfif>
Although this may be recursion given it was written in 2004 I kind of doubt it
Adding screen shots of searches
If anyone else runs into this. In CF8, and presuming earlier versions, you could put a cfm file into the ColdFusion8\wwwroot\WEB-INF\cftags Directory and that file in this case ColdFusion8\wwwroot\WEB-INF\cftags\link.cfm Then acts as any other cftag.
I was able to find the person who originally build this app in 2004 and he told me that they did it this way to avoid typing the underscore that they would have typed if they'd done it as a custom tag.
I kind of get it since this tag is used everywhere in the app, literally hundreds of times. Bit boy with a bitch to find.
Now all I have to do is figure out how to move it to the Lucee world in a similar fashion. So it instanciates the same way.
Thanks #Leigh for all your help, you are always amazing!
Adding more information
if there are files in the WEB-INF\lucee\library\tag the corresponding Lucee directory is WEB-INF\lucee\library\tag. These files are read on load and then able to be used as any other cf tag.
For example if you have file WEB-INF\lucee\library\tag\link.cfm it can be called by `cflink'.
Seems like a cool idea but a bit of a bitch for someone to find 10 years after the fact

ColdFusion IDE equivalent to Visual Studio's "go to definition" and "find usages"

Do any of the ColdFusion IDEs/IDE plugins allow you to perform actions similar to Visual Studio's go to definition and find usages (some details of which are on this page)?
For example, in one .cfc file I might have:
<cfset variables.fooResult = CreateObject(
"component",
"Components.com.company.myClass").fooMethod()>
And in myClass.cfc I have:
<cffunction name="fooMethod" access="public">
<!-- function body -->
</cffunction>
If I have my cursor set over .fooMethod in the first file, a go to definition action should place me on the declaration of that method in myClass.cfc.
At present I'm using the CFEclipse plugin for Eclipse to view some legacy ColdFusion.
CFEclipse doesn't have this functionality, partly because CFML is a dynamic language with a fair bit of complexity parsing-wise.
You can use regex searching to get you most of the way there in most cases.
Function Definitions
To find a function definition, most times searching for...
(name="|ion )methodname
...is enough, and quicker than the more thorough form of:
(<cffunction\s+name\s*=\s*['"]|\bfunction\s+)methodname
Function Calls
To find a function call, against just do:
methodname\s*\(
Though against you might need to be more thorough, with:
['"]methodname['"]\s*\]\s*\(
...if bracket notation has been used.
You might also want to check for cfinvoke usage:
<cfinvoke[^>]+?method\s*=\s*['"]methodname
Of course, neither of these methods will find if you have code that is:
<cfset meth = "methodname" />
<cfinvoke ... method="#meth#" />
...nor any other form of dynamic method names.
If you really need to be thorough and find all instances, it's probably best to search for the method name alone (or wrapped as \bmethodname\b), and manually walk through the code for any variables using it.
IF you use
<cfset c = new Components.com.company.myClass()>
<cfset variables.fooResult = c.fooMethod()>
I believe in CFBuilder you can click Ctrl and the CFC class and method will turn into a hyperlink. See "Code insight" on http://www.adobe.com/ca/products/coldfusion-builder/features.html It works when it work, it doesn't when mapping is incorrect or certain syntax may not be supported. I'm not sure if they support the CreateObject() way.
There's no find usage as CF is not a static language. However, the Find can find what you need most of the time unless the code invokes method dynamically or uses Evaulate()

cfInclude without cfoutput tags

Ok, I have template files which I know will require to be between <cfoutput> tags, however placing a <cfoutput> tag around a <cfinclude> won't work, and anything with a <cfmodule> won't work as that doesn't allow me to manipulate the variables scope.
So, any ideas - no matter how complex - which would allow me to include such a template file and have it act as if it's between <cfoutput> tags?
Bit of context: It's for a 'framework' I am working on and requiring every template file to start and end with a <cfoutput> tag seems a real waste, especially because the less 'coldfusiony' the template files look, the better IMO.
I was going to suggest the render() option, with the caveat it's a bloody awful bit of functionality in OpenBDML (or whatever they want to call their version of CFML), and I think should be avoided. I can't see how it doesn't cause the CFML to be recompiled every request, which is a helluva overhead. I think you're better off modifying the mark-up when it gets saved/read to wrap/unwrap it in <cfoutput> tags, that way the resultant CFML will only be recompiled when the file actually changes. Which will be really a lot less often than it's read.
Prompted by your question, I did a bit of a write up on the CFML compile process, showing why having the <cfoutput> tags in a separate file doesn't work. Apologies it took so long to write & follow-up with here.
What we do in wheels is just wrap the cfinclude with a cfsavecontent tag
<cffunction name="renderInclude">
<cfargument name="template" value="string" required="true">
<cfset var myOutput = "">
<cfsavecontent variable="myOutput"><cfoutput><cfinclude template="#arguments.template#"></cfoutput></cfsavecontent>
<cfreturn trim(myOutput)>
</cffunction>
Found an OpenBD specific way to solve this problem. Apparently I wasn't the only one who encountered this problem and OpenBD contains a useful render() which takes care of evaluating cfml content. So I ended up with
<cfset cfml = fileRead(expandPath(...))>
...
<cfoutput>#render("<cfoutput>"&cfml&"</cfoutput>")#</cfoutput>
It's not a beautiful solution, as I destroy the per page compilation the engine would otherwise do, however as the cfml is relatively simple on these pages I assume this not to be too much of an issue. At least it should be less of a performance hit than actually writing the file to disk.

What security scripts/code do you add to your application.cfm?

I am working on redoing our company's code, and I want to have a clear, easy to read, and reasonably secure application.cfm.
And no, we are not using application.cfc. So let's not discuss that please.
Just want to know what scripts you would add for security.
I am using coldfusion 8 standard, sql 2008.
Here is one of the scripts I am currently using, but I want to hear from some other coldfusion programmers.
<cfset temp = cleanScopes('form,url') />
<!--- another method to clean url/form data from http://www.garyrgilbert.com/tools/coldfusion/cleanScopes.cfm.txt --->
<cffunction name="cleanScopes" access="public" returntype="void">
<cfargument name="scopesToClean" type="string" required="yes">
<cfargument name="charlist" type="string" required="no" default="">
<cfscript>
reTags ="<[^/>]*>|</.*>";
</cfscript>
<cfloop list="#scopestoClean#" index="scopeName">
<cfif not findnocase("multipart/form-data",cgi.CONTENT_TYPE)>
<cfscript>
s=Evaluate(scopeName);
for(field in s)
if (isSimpleValue(s[field])){
if(reTags neq '')
do { prev=s[field];
s[field]=REReplaceNoCase(s[field],reTags,"","ALL");
} while (prev NEQ s[field]);
structUpdate(s,field,prev);
if (charlist neq '')
s[field] = replacelist(s[field],charlist,'');
}
</cfscript>
</cfif>
</cfloop>
<cfreturn>
</cffunction>
Thank you for your time.
I would advise against attempting to catch everything in a global fashion. There will inevitably be a few things that slip through the cracks, no matter how complex and convoluted your global protection code gets.
Instead, the "correct" (for what it's worth) method is to sanitize all content being presented on a page (or in an email, etc) -- during output -- that began its life as user input.
That said, take a look at OWASP. They have excellent libraries for protecting from all kinds of attacks, including the various ones you mention (sqli, xss, crlf). A coworker of mine recently wrapped up some of those libraries into a CFC that we can use in our applications, and explained how to use it on our developers blog:
AntiSamy
If your application accepts user generated HTML, say blog comments for example, you need to make sure you sanitize your input to prevent XSS attacks. You wouldn’t want someone to be able to enter malicious code in your blog comments so you need some way to filter the input. Enter AntiSamy. AntiSamy allows you to easily filter user generated HTML according to what it terms policies. AntiSamy is a Java project, so I have packaged it into a CFC for easy use from ColdFusion.
The simplist way to use AntiSamy is to create an instance of the AntiSamy component (cfc.owasp.AntiSamy) and call the getCleanHTML() method on the input.
<cfset antisamy = CreateObject("component","cfc.owasp.antisamy") />
<cfset cleanHTML = antisamy.scan(form.someInput) />
This will run AntiSamy with the default (fairly permissive) policy file and return the clean HTML markup.
ESAPI Encoder
The next library I’ve brought over from the OWASP project is the ESAPI Encoder. Again this is a Java project which I have wrapped in a CFC for easier use. The encoder provides several methods for encoding beyond those included with ColdFusion. Some of the more useful methods include encodeForJavaScript(), encodeForHTMLAttribute(), and encodeForCSS(). Using the component is pretty straight forward, just instantiate it and call the appropriate method.
<cfset encoder = CreateObject("component","cfc.owasp.Encoder") />
<cfset html = encoder.encodeForHTML("<body onload=""alert('XSS')"">Test</body>") />
One very useful method this library provides is the canonicalize method. The documentation from the beta version of the ESAPI Encoder gives a good description of what this method does.
However, if you insist on a global solution, why reinvent the wheel? Why not try out something like FuseGuard. The price is probably less than the cost of the development-hours that would be spent cobbling together, debugging, and dealing with security problems that break through your home-grown system.
Personally, I'm not really sure this "global" approach is the best. I check all incoming data in all models that accept external data, with specific validation rules for each situation. So additional layer looks overkill.
Such scripts wont protect you from putting string into the numeric id passed into the URL -- you have to check it any way. You have to use HTMLEditFormat/XMLFormat in the views any way, and so on.
P.S. List loop for CFScript:
for (i=1; i LTE ListLen(scopestoClean); i++) {
scopeName = ListGetAt(scopestoClean,i);
//... following code
}