Viewing Entries For June 2010  [clear date selection]

Painlessly Updating Open BlueDragon

I recently wrote a modest shell script to make updating an installation of Open BlueDragon less cumbersome. I reported an issue with a nightly build, and I wanted to be able to switch between build versions reliably and quickly. The script, available as openbluedragon-nightly-updater.sh, will download and archive the nightly build and then deploy to web application server configured. My development environment is Apache Tomcat on Mac OS X 10.5/10.6. I create a directory in $HOME called Servers into which I download tarball distributions of Tomcat. I then create a symbolic link to the current version as ~/Servers/Tomcat. I use the ROOT context for simplicity. I keep old nightly builds in my ~/Downloads directory. Therefore, the configuration in the update script looks like this:

NIGHTLY="OpenBlueDragon-Nightly-`date +%Y-%m-%d`.zip" SERVER="$HOME/Servers/Tomcat" DEPLOY="$SERVER/webapps" CONTEXT="ROOT" URL="http://www.openbluedragon.org/download/nightly/openbd.war" ARCHIVE="$HOME/Downloads/$NIGHTLY"

The script has two options: (-m) minimal or full update, and (-f) local file or remote download. With the minimal update, it just replaces the $DEPLOY/$CONTEXT/WEB-INF/lib/OpenBlueDragon.jar file. The full update replaces all of the Open BlueDragon JAR files, as well as the administration application and manual. It does not, however delete the existing Open BlueDragon configuration in $DEPLOY/$CONTEXT/WEB-INF/bluedragon. This is important to me because I don't want to lose the current settings for datasources, mail, debugging, and whatnot. I also want to keep all the symbolic links to my CFML applications in $DEPLOY/$CONTEXT in tact.

While working on a problem today, I wanted to verify that the issue wasn't introduced with last night's build. I just ran the following commands to revert to last week's build:

~/Servers/Tomcat/bin/catalina.sh stop ~/Workspace/admin/coldfusion/openbluedragon-nightly-updater.sh -m -f \     ~/Downloads/OpenBlueDragon-Nightly-2010-06-12.zip ~/Servers/Tomcat/bin/catalina.sh start

In less time than it takes to get another Diet Coke, the installation of Open BlueDragon was running an arbitrary version. It turned out that the issue I was troubleshooting had nothing to do with Open BlueDragon -- it was an error in my MXUnit test case. To get running again on the latest version, I ran the script without any arguments.

Preventing SCCS Data Leaks

Many people, right or wrong, deploy CFML applications to the web server by performing a checkout a source code control system, such as Subversion or Git. This has the effect of placing repository information in directories with the rest of the files; ${APPROOT}/**/.svn and ${APPROOT}/.git, for example. It's possible that this repository information (containing the code in plain-text and configuration files) will be exposed by the web server. That would be bad.

Whether the repository data is visible to an HTTP client depends on several factors: the OS, the web server and configuration, the directory and file permissions and OS- and filesystem-specific attributes. Probably the two most common environments are Windows with IIS and Linux with Apache. In the first case, IIS by default is configured to hide files and directories with the NTFS hidden attribute. Since both Subversion and Git create their repository directories with this flag enabled, the default scenario on Windows/IIS is safe. However, the same is not true for Linux/Apache (or Apache on Windows, for that matter).

Apache has always shipped, to the best of my knowledge, with a server-wide directive to prevent disclosing .htaccess and .htpasswd files:

<FilesMatch "^\.ht"> Order allow,deny Deny from all Satisfy All </FilesMatch>

It's not enough, I'm afraid, to remove the "ht" from the regex. To properly secure the SCCS artifacts, I like to use the trusty mod_rewrite module:

RewriteRule /(\.svn|\.git)/.* - [L,F]

And while I'm on the topic of using mod_rewrite to secure an application, here are some rules I use to prevent any similar shenanigans:

RewriteRule ^/app/(config|filters|listeners|plugins|properties|views)/.* - [L,F] RewriteRule ^/(MachII|MachIIDashboard|coldspring|transfer|cfpayment)/.* - [L,F] RewriteRule ^/(db|gen|model|taglib)/.* - [L,F]

Please feel free to comment. Oh wait, I'm lame and haven't enable comments on this blog. I suppose you could send them to @jlamoree instead.

Absolute, Relative, and Temporary Paths

I've often needed to programmatically determine a component's relative (possibly mapped) path, as well as the absolute path (with symbolic links resolved) to the CFC file. Getting the absolute path is a cinch using the path element returned by the getMetadata() function. However, the relative path must be gleaned from the name by replacing the dot-notation with directory separators. No, it's not rocket surgery.

<cffunction name="getPaths" returntype="struct" access="private" output="false">   <cfset var md = getMetaData(this)/>   <cfset var paths = structNew()/>   <cfset var name = listLast(md.name, ".")/>   <cfset paths.relative = "/" & listChangeDelims(reReplaceNoCase(md.name, name, ""), "/", ".")/>   <cfif not right(paths.relative, 1) eq "/">     <cfset paths.relative = paths.relative & "/"/>   </cfif>   <cfset paths.absolute = getDirectoryFromPath(md.path)/>   <cfset paths.temp = getTempDirectory()/>   <cfreturn paths/> </cffunction>

Dumping out the structure returned by getPaths() yields the following:

The temp directory of the CFML engine is also returned, should you need that too.

Visually Unique Character Sets

A moment ago I asked both of my followers on Twitter about character sets that eliminate visually similar symbols. Neither of them replied yet, but I thought I'd expand on the question. I was working on a token maker that generates random sets of characters for use as unique identifiers or serial numbers. In the following code block, see the UNIQUE character set -- it doesn't contain characters that could be recognized incorrectly when printed or in an e-mail (1,l,0,O,2,Z 5,S...).

<cfset variables.characters = structNew()/> <cfset variables.characters.ALPHA_LOWER = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z"/> <cfset variables.characters.ALPHA_UPPER = ucase(variables.characters.ALPHA_LOWER)/> <cfset variables.characters.ALPHA = variables.characters.ALPHA_LOWER & "," & variables.characters.ALPHA_UPPER/> <cfset variables.characters.NUMERIC = "0,1,2,3,4,5,6,7,8,9"/> <cfset variables.characters.ALPHANUMERIC = variables.characters.NUMERIC & "," & variables.characters.ALPHA/> <cfset variables.characters.ALPHANUMERIC_LOWER = variables.characters.NUMERIC & "," & variables.characters.ALPHA_LOWER/> <cfset variables.characters.ALPHANUMERIC_UPPER = variables.characters.NUMERIC & "," & variables.characters.ALPHA_UPPER/> <cfset variables.characters.UNIQUE = "3,4,5,6,7,8,9,a,A,b,B,c,C,d,D,e,E,F,G,h,H,j,J,k,K,L,m,M,n,N,p,P,Q,r,R,t,T,u,U,v,V,w,W,x,X,y,Y"/> <cfset variables.characters.UNIQUE_LOWER = _listDeleteEmptyItems(reReplace(variables.characters.UNIQUE, "[A-Z]", "", "all"))/> <cfset variables.characters.UNIQUE_UPPER = _listDeleteEmptyItems(reReplace(variables.characters.UNIQUE, "[a-z]", "", "all"))/>

The resulting variable contains a variety of character sets that can be used to create any length of random string.

So, if you do know what such a unique character set is called, do let me know.

Oh, one other thing I should mention. I created the function _listDeleteEmptyItems() with a leading underscore in case one of the CFML engines implements a function of the same name. With my luck, it would happen next week.