root/trunk/website/blog/cfformprotect/cffpVerify.cfc @ 15

Revision 5, 29.6 kB (checked in by DanWilson, 17 years ago)

Initial Commit Of ModelGlue? Website (upgrade to blogcfc 511)

Line 
1<cfcomponent output="false" hint="
2<pre>
3DEVELOPER NOTES:
4
5*******************************************************************************************************
6This component is a CFC implementation of Jacob Munson's cffpVerify.cfm (part of CFFormProtect) written
7by Dave Shuck dshuck@gmail.com.  All calculations/algorithms are a direct port of Jacob's original code,
8with exceptions noted in the NOTES section below.
9*******************************************************************************************************
10
11- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
12TEMPLATE    : cffpVerify.cfc
13
14CREATED     : 23 Mar 2007
15
16USAGE       : Perform various tests on a form submission to ensure that a human submitted it.
17
18DEPENDANCY  : NONE
19
20NOTES       : Dave Shuck - created
21                          Dave Shuck - 23 Mar 2007 - Added testTooManyUrls() method and call to the method in testSubmission()
22                          Dave Shuck - 23 Mar 2007 - Removed the '0' padding in FormTime in testTimedSubmission() which was causing
23                                                                                        consistent failure on that test
24                          Dave Shuck - 24 Mar 2007 - Added logFailure() method and the call to the method in testSubmission().  This
25                                                                                        code is still backwards compatable with older ini files that do not make use of
26                                                                                        the properties 'logFailedTests' and 'logFile'
27                          Dave Shuck - 26 Mar 2007 - Altered the FormTime in testTimedSubmission() to use NumberFormat as the previous
28                                                                                        change caused exceptions before 10:00am.  (see comments in method)     
29                          Mary Jo Sminkey - 18 July 2007 - Added new function 'testSpamStrings' which allows the user to configure a list
30                                                                                                of text strings to test the form against. Similar to using Akismet but with no
31                                                                                                cost involved for commercial use and can be configured as needed for the spam
32                                                                                                received. Update Akismet function to log to same file and not log as passed if
33                                                                                                the key validation failed.     
34- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35</pre>
36">
37
38        <cffunction name="init" access="public" output="false" returntype="cffpVerify">
39                <cfargument name="ConfigPath" required="false" default="#ExpandPath("./cfformprotect")#" type="string" />
40                <cfscript>
41                setConfig(arguments.ConfigPath);
42                return this;
43                </cfscript>
44        </cffunction>
45       
46        <cffunction name="getConfig" access="public" output="false" returntype="struct">
47                <cfreturn variables.Config />
48        </cffunction>
49       
50        <cffunction name="setConfig" access="private" output="false" returntype="void">
51                <cfargument name="ConfigPath" required="true" />
52                <cfscript>
53                var IniEntries = GetProfileSections(arguments.ConfigPath & "/cffp.ini.cfm").CFFormProtect;
54                var i = "";
55                variables.Config = StructNew();
56               
57                for (i=1;i LTE ListLen(IniEntries);i=i+1)       {
58                        variables.Config[ListGetAt(IniEntries,i)] = GetProfileString(arguments.ConfigPath & "/cffp.ini.cfm","CFFormProtect",ListGetAt(IniEntries,i));
59                }
60                //set logfile
61                if (NOT Len(variables.Config.logFile))  { variables.Config.logFile = "CFFormProtect"; }
62                </cfscript>
63        </cffunction>
64       
65        <cffunction name="testSubmission" access="public" output="false" returntype="any">
66                <cfargument name="FormStruct" required="true" type="struct" />
67                <cfscript>
68                var Pass = true;
69                // each time a test fails, totalPoints is incremented by the user specified amount
70                var TotalPoints = 0;
71                // setup a variable to store a list of tests that failed, for informational purposes
72                var TestsResults = StructNew();
73               
74                // Begin tests         
75                // Test for mouse movement
76                try     {
77                        if (getConfig().mouseMovement)  {
78                                TestResults.MouseMovement = testMouseMovement(arguments.FormStruct);
79                                if (NOT TestResults.MouseMovement.Pass) {
80                                        // The mouse did not move
81                                        TotalPoints = TotalPoints + getConfig().mouseMovementPoints;
82                                }
83                        }
84                }
85                catch(any excpt)        { /* an error occurred on this test, but we will move one */ } 
86
87               
88                // Test for used keyboard
89                try     {
90                        if (getConfig().usedKeyboard)   {
91                                TestResults.usedKeyboard = testUsedKeyboard(arguments.FormStruct);
92                                if (NOT TestResults.usedKeyboard.Pass)  {
93                                        // No keyboard activity was detected
94                                        TotalPoints = TotalPoints + getConfig().usedKeyboardPoints;                     
95                                }
96                        }                                       
97                }
98                catch(any excpt)        { /* an error occurred on this test, but we will move one */ } 
99
100               
101                // Test for time taken on the form
102                try     {
103                        if (getConfig().timedFormSubmission)    {
104                                TestResults.timedFormSubmission = testTimedFormSubmission(arguments.FormStruct);
105                                if (NOT TestResults.timedFormSubmission.Pass)   {
106                                        // Time was either too short, too long, or the form field was altered
107                                        TotalPoints = TotalPoints + getConfig().timedFormPoints;                       
108                                }
109                        }                                               
110                }
111                catch(any excpt)        { /* an error occurred on this test, but we will move one */ } 
112
113
114                // Test for empty hidden form field
115                try     {
116                        if (getConfig().hiddenFormField)        {
117                                TestResults.hiddenFormField = testHiddenFormField(arguments.FormStruct);
118                                if (NOT TestResults.hiddenFormField.Pass)       {
119                                        // The submitter filled in a form field hidden via CSS
120                                        TotalPoints = TotalPoints + getConfig().hiddenFieldPoints;                     
121                                }
122                        }                       
123                }
124                catch(any excpt)        { /* an error occurred on this test, but we will move one */ } 
125
126               
127                // Test Akismet
128                //try   {
129                        if (getConfig().akismet)        {
130                                TestResults.akismet = testAkismet(arguments.FormStruct);
131                                if (NOT TestResults.akismet.Pass)       {
132                                        // Akismet says this form submission is spam
133                                        TotalPoints = TotalPoints + getConfig().akismetPoints;
134                                }
135                        }               
136                //}
137                //catch(any excpt)      { /* an error occurred on this test, but we will move one */ } 
138
139               
140                // Test tooManyUrls
141                try     {
142                        if (getConfig().tooManyUrls)    {
143                                TestResults.tooManyUrls = TestTooManyUrls(arguments.FormStruct);
144                                if (NOT TestResults.tooManyUrls.Pass)   {
145                                        // Submitter has included too many urls in at least one form field
146                                        TotalPoints = TotalPoints + getConfig().tooManyUrlsPoints;
147                                }
148                        }                       
149                }
150                catch(any excpt)        { /* an error occurred on this test, but we will move one */ } 
151
152                // Test spamStrings
153                try     {
154                        if (getConfig().teststrings)    {
155                                TestResults.SpamStrings = testSpamStrings(arguments.FormStruct);
156                                if (NOT TestResults.SpamStrings.Pass)   {
157                                        // Submitter has included a spam string in at least one form field
158                                        TotalPoints = TotalPoints + getConfig().spamStringPoints;
159                                }
160                        }                       
161                }
162                catch(any excpt)        { /* an error occurred on this test, but we will move one */ } 
163               
164                // Test Project Honey Pot
165                try     {
166                        if (getConfig().projectHoneyPot)        {
167                                TestResults.ProjHoneyPot = testProjHoneyPot(arguments.FormStruct);
168                                if (NOT TestResults.ProjHoneyPot.Pass)  {
169                                        // Submitter has included a spam string in at least one form field
170                                        TotalPoints = TotalPoints + getConfig().projectHoneyPotPoints;
171                                }
172                        }                       
173                }
174                catch(any excpt)        { /* an error occurred on this test, but we will move one */ } 
175
176                // Compare the total points from the spam tests to the user specified failure limit
177                if (TotalPoints GTE getConfig().failureLimit)   {
178                        Pass = false;   
179                        try     {
180                                if (getConfig().emailFailedTests)       {
181                                        emailReport(TestResults=TestResults,FormStruct=FormStruct,TotalPoints=TotalPoints);     
182                                }                               
183                        }
184                        catch(any excpt)        { /* an error has occurred emailing the report, but we will move on */ }
185                        try     {
186                                if (getConfig().logFailedTests) {
187                                        logFailure(TestResults=TestResults,FormStruct=FormStruct,TotalPoints=TotalPoints,LogFile=getConfig().logFile); 
188                                }                               
189                        }
190                        catch(any excpt)        { /* an error has occurred logging the spam, but we will move on */ }
191                }
192                return pass;
193                </cfscript>
194        </cffunction>
195       
196        <cffunction name="testMouseMovement" access="private" output="false" returntype="struct"
197                                hint="I make sure this form field exists, and it has a numeric value in it (the distance the mouse traveled)">
198                <cfargument name="FormStruct" required="true" type="struct" />
199                <cfscript>
200                var Result = StructNew();
201                Result.Pass = false;
202                if (StructKeyExists(arguments.FormStruct,"formfield1234567891") AND IsNumeric(arguments.FormStruct.formfield1234567891))        {
203                        Result.Pass = true;
204                }       
205                return Result;
206                </cfscript>
207        </cffunction>   
208       
209        <cffunction name="testUsedKeyboard" access="private" output="false" returntype="struct"
210                                hint="I make sure this form field exists, and it has a numeric value in it (the amount of keys pressed by the user)">
211                <cfargument name="FormStruct" required="true" type="struct" />
212                <cfscript>
213                var Result = StructNew();
214                Result.Pass = false;
215                if (StructKeyExists(arguments.FormStruct,"formfield1234567892") AND IsNumeric(arguments.FormStruct.formfield1234567892))        {
216                        Result.Pass = true;
217                }       
218                return Result;
219                </cfscript>             
220        </cffunction>
221       
222        <cffunction name="testTimedFormSubmission" access="private" output="false" returntype="struct"
223                                        hint="I check the time elapsed from the begining of the form load to the form submission">
224                <cfargument name="FormStruct" required="true" type="struct" />
225                <cfscript>
226                var Result = StructNew();
227                var FormDate = "";
228                var FormTime = "";
229                var FormDateTime = "";
230                //var FormTimeElapsed = "";
231               
232                Result.Pass = true;
233                                                               
234                // Decrypt the initial form load time
235                if (StructKeyExists(arguments.FormStruct,"formfield1234567893") AND ListLen(form.formfield1234567893) eq 2)     {
236                        FormDate = ListFirst(form.formfield1234567893)-19740206;
237                        if (Len(FormDate) EQ 7) {
238                                FormDate = "0" & FormDate;     
239                        }
240                        FormTime = ListLast(form.formfield1234567893)-19740206;
241                        if (Len(FormTime))      {
242                                // in original form, FormTime was always padded with a "0" below.  In my testing, this caused the timed test to fail
243                                // consistantly after 9:59am due to the fact it was shifting the time digits one place to the right with 2 digit hours. 
244                                // To make this work I added NumberFormat()
245                                FormTime = NumberFormat(FormTime,000000);
246                        }
247                       
248                        FormDateTime = CreateDateTime(Left(FormDate,4),Mid(FormDate,5,2),Right(FormDate,2),Left(FormTime,2),Mid(FormTime,3,2),Right(FormTime,2));
249                        // Calculate how many seconds elapsed
250                        Result.FormTimeElapsed = DateDiff("s",FormDateTime,Now());
251                        if (Result.FormTimeElapsed LT getConfig().timedFormMinSeconds OR Result.FormTimeElapsed GT getConfig().timedFormMaxSeconds)     {
252                                Result.Pass = false;
253                        }
254                }       
255                else    {
256                        Result.Pass = false;
257                }
258                return Result;
259                </cfscript>
260        </cffunction>
261       
262        <cffunction name="testHiddenFormField" access="private" output="false" returntype="struct"
263                                hint="I make sure the CSS hidden form field doesn't have a value">
264                <cfargument name="FormStruct" required="true" type="struct" />
265                <cfscript>
266                var Result = StructNew();
267                Result.Pass = false;
268                if (StructKeyExists(arguments.FormStruct,"formfield1234567894") AND NOT Len(arguments.FormStruct.formfield1234567894))  {
269                        Result.Pass = true;
270                }       
271                return Result;         
272                </cfscript>
273        </cffunction>
274
275        <cffunction name="testAkismet" access="private" output="false" returntype="struct"
276                                hint="I send form contents to the public Akismet service to validate that it's not 'spammy'">
277                <cfargument name="FormStruct" required="true" type="struct" />
278                <cfscript>
279                var Result = StructNew();
280                var AkismetKeyIsValid = false;
281                var AkismetHTTPRequest = true;
282                var logfile = getConfig().logFile;
283                Result.Pass = true;
284                Result.ValidKey = false;
285                </cfscript>
286       
287                <cftry>
288                        <!--- validate the Akismet API key --->
289                        <cfhttp url="http://rest.akismet.com/1.1/verify-key" timeout="10" method="post">
290                                <cfhttpparam name="key" type="formfield" value="#getConfig().akismetAPIKey#" />
291                                <cfhttpparam name="blog" type="formfield" value="#getConfig().akismetBlogURL#" />
292                        </cfhttp>
293                        <cfcatch type="any">
294                                <cfset AkismetHTTPRequest = false />
295                        </cfcatch>
296                </cftry>
297                <cfif AkismetHTTPRequest AND Trim(cfhttp.FileContent) EQ "valid">
298                        <cfset AkismetKeyIsValid = true />
299                        <cfset Result.ValidKey = true />
300                </cfif>
301                <cfif AkismetKeyIsValid>
302                        <cftry>
303                                <!--- send form contents to Akismet API --->
304                                <cfhttp url="http://#getConfig().akismetAPIKey#.rest.akismet.com/1.1/comment-check" timeout="10" method="post">
305                                        <cfhttpparam name="key" type="formfield" value="#getConfig().akismetAPIKey#" />
306                                        <cfhttpparam name="blog" type="formfield" value="#getConfig().akismetBlogURL#" />
307                                        <cfhttpparam name="user_ip" type="formfield" value="#cgi.remote_addr#" />
308                                        <cfhttpparam name="user_agent" type="formfield" value="CFFormProtect/1.0 | Akismet/1.11" />
309                                        <cfhttpparam name="referrer" type="formfield" value="#cgi.http_referer#" />
310                                        <cfhttpparam name="comment_author" type="formfield" value="#arguments.FormStruct[getConfig().akismetFormNameField]#" />
311                                        <cfif Len(getConfig().akismetFormEmailField)>
312                                                <cfhttpparam name="comment_author_email" type="formfield" value="#arguments.FormStruct[getConfig().akismetFormEmailField]#" />
313                                        </cfif>
314                                        <cfif Len(getConfig().akismetFormURLField)>
315                                                <cfhttpparam name="comment_author_url" type="formfield" value="#arguments.FormStruct[getConfig().akismetFormURLField]#" />
316                                        </cfif>
317                                        <cfhttpparam name="comment_content" type="formfield" value="#arguments.FormStruct[getConfig().akismetFormBodyField]#" />
318                                </cfhttp>
319                                <cfcatch type="any">
320                                        <cfset akismetHTTPRequest = false />
321                                </cfcatch>
322                        </cftry>
323                                <!--- check Akismet results --->
324                                <cfif AkismetHTTPRequest AND Trim(cfhttp.FileContent)>
325                                        <!--- Akismet says this form submission is spam --->
326                                        <cfset Result.Pass = false />
327                                </cfif>
328                <cfelse>
329                        <cflog file="#logfile#" text="Akismet API Key is invalid" />
330                </cfif>
331                <cfreturn Result />
332        </cffunction>
333       
334        <cffunction name="testTooManyUrls" access="private" output="false" returntype="struct"
335                                hint="I test whether too many URLs have been submitted in fields">
336                <cfargument name="FormStruct" required="true" type="struct" />
337                <cfscript>
338                var Result = StructNew();
339                var i = "";
340                // Make a duplicate since this is passed by reference and we don't want to modify the original data
341                var FormStructCopy = Duplicate(arguments.FormStruct);
342                var UrlCount = "";
343               
344                Result.Pass = true;
345                for (i=1;i LTE ListLen(arguments.FormStruct.FieldNames);i=i+1)  {
346                        UrlCount = -1;
347                        while (FindNoCase("http://",FormStructCopy[ListGetAt(arguments.FormStruct.FieldNames,i)]))      {
348                                FormStructCopy[ListGetAt(arguments.FormStruct.FieldNames,i)] = ReplaceNoCase(FormStructCopy[ListGetAt(arguments.FormStruct.FieldNames,i)],"http://","","one");
349                                UrlCount = UrlCount + 1;
350                        }       
351                        if (UrlCount GTE getConfig().tooManyUrlsMaxUrls)        {
352                                Result.Pass = false;
353                                break; 
354                        }
355                }
356                return Result;
357                </cfscript>
358        </cffunction>
359       
360        <cffunction name="listFindOneOf" output="false" returntype="boolean">
361                <cfargument name="texttosearch" type="string" required="yes"/>
362                <cfargument name="values" type="string" required="yes"/>
363                <cfargument name="delimiters" type="string" required="no" default=","/>
364                <cfset var value = 0/>
365                <cfloop list="#arguments.values#" index="value" delimiters="#arguments.delimiters#">
366                        <cfif FindNoCase(value, arguments.texttosearch)>
367                                <cfreturn false />
368                        </cfif>
369                </cfloop>
370                <cfreturn true />
371        </cffunction>
372
373        <cffunction name="testSpamStrings" access="private" output="false" returntype="struct"
374                                hint="I test whether any of the configured spam strings are found in the form submission">
375                <cfargument name="FormStruct" required="true" type="struct" />
376                <cfscript>
377                var Result = StructNew();
378                var value = 0;
379                var teststrings = getConfig().spamstrings;
380                var checkfield = '';
381                Result.Pass = true;
382               
383                // Loop through the list of spam strings to see if they are found in the form submission               
384                for (checkfield in arguments.FormStruct)        {
385                        if (Result.Pass IS true)        {
386                                Result.Pass = listFindOneOf(arguments.FormStruct[checkfield],teststrings);
387                        }
388                }
389                return Result;
390                </cfscript>
391        </cffunction>
392
393        <cffunction name="testProjHoneyPot" access="private" output="false" returntype="struct"
394                                hint="I send the user's IP address to the Project Honey Pot service to check if it's from a known spammer.">
395                <cfargument name="FormStruct" required="true" type="struct" />
396                <cfset var Result = StructNew()>
397                <cfset var apiKey = getConfig().projectHoneyPotAPIKey>
398                <cfset var visitorIP = cgi.remote_addr> <!--- 93.174.93.221 is known to be bad --->
399                <cfset var reversedIP = "">
400                <cfset var addressFound = 1>
401                <cfset var isSpammer = 0>
402                <cfset var inetObj = "">
403                <cfset var hostNameObj = "">
404                <cfset var projHoneypotResult = "">
405                <cfset var resultArray = "">
406                <cfset var threatScore = "">
407                <cfset var classification = "">
408                <cfset Result.Pass = true>
409               
410                <!--- Setup the DNS query string --->
411                <cfset reversedIP = listToArray(visitorIP,".")>
412                <cfset reversedIP = reversedIP[4]&"."&reversedIP[3]&"."&reversedIP[2]&"."&reversedIP[1]>
413
414                <cftry>
415                        <!--- Query Project Honeypot for this address --->
416                        <cfset inetObj = createObject("java", "java.net.InetAddress")>
417                        <cfset hostNameObj = inetObj.getByName("#apiKey#.#reversedIP#.dnsbl.httpbl.org")>
418                        <cfset projHoneypotResult = hostNameObj.getHostAddress()>
419                        <cfcatch type="java.net.UnknownHostException">
420                                <!--- The above Java code throws an exception when the address is not
421                                                        found in the Project Honey Pot database. --->
422                                <cfset addressFound = 0>
423                        </cfcatch>
424                </cftry>
425               
426                <cfif addressFound>
427                        <cfset resultArray = listToArray(projHoneypotResult,".")>
428                        <!--- resultArray[3] is the threat score for the address, rated from 0 to 255.
429                                                resultArray[4] is the classification for the address, anything higher than
430                                                1 is either a harvester or comment spammer --->
431                        <cfset threatScore = resultArray[3]>
432                        <cfset classification = resultArray[4]>
433                        <cfif (threatScore gt 10) and (classification gt 1)>
434                                <cfset isSpammer=isSpammer+1>
435                        </cfif>
436                </cfif>
437               
438                <cfif isSpammer>
439                        <cfset Result.Pass = false>
440                </cfif>
441               
442                <cfreturn Result>
443        </cffunction>
444
445        <cffunction name="emailReport" access="private" output="false" returntype="void">
446                <cfargument name="TestResults" required="true" type="struct" />
447                <cfargument name="FormStruct" required="true" type="struct">
448                <cfargument name="TotalPoints" required="true" type="numeric" />
449                <cfscript>
450                var falsePositiveURL = "";
451                var missedSpamURL = "";
452                </cfscript>
453                <!--- Here is where you might want to make some changes, to customize what happens
454                                if a spam message is found.  depending on your system, you can either just use
455                                my code here, or email yourself the failed test, or plug into your system
456                                in the best way for your needs --->
457                        <!---  --->
458                                       
459                <cfmail
460                        from="#getConfig().emailFromAddress#"
461                        to="#getConfig().emailToAddress#"
462                        subject="#getConfig().emailSubject#"
463                        server="#getConfig().emailServer#"
464                        username="#getConfig().emailUserName#"
465                        password="#getConfig().emailPassword#"
466                        type="html">
467                                This message was marked as spam because:
468                                <ol>
469                                        <cfif StructKeyExists(arguments.TestResults,"mouseMovement") AND NOT arguments.TestResults.mouseMovement.Pass>
470                                        <li>No mouse movement was detected.</li>
471                                        </cfif>
472                                       
473                                        <cfif StructKeyExists(arguments.TestResults,"usedKeyboard") AND NOT arguments.TestResults.usedKeyboard.Pass>
474                                        <li>No keyboard activity was detected.</li>
475                                        </cfif>
476                                       
477                                        <cfif StructKeyExists(arguments.TestResults,"timedFormSubmission") AND NOT arguments.TestResults.timedFormSubmission.Pass>
478                                                <cfif StructKeyExists(arguments.FormStruct,"formfield1234567893")>
479                                                <li>The time it took to fill out the form was
480                                                        <cfif arguments.FormStruct.formfield1234567893 lt getConfig().timedFormMinSeconds>
481                                                                too short.
482                                                        <cfelseif arguments.FormStruct.formfield1234567893 gt getConfig().timedFormMaxSeconds>
483                                                                too long.
484                                                        </cfif>
485                                                        It took them #arguments.FormStruct.formfield1234567893# seconds to submit the form, and your allowed
486                                                        threshold is #getConfig().timedFormMinSeconds#-#getConfig().timedFormMaxSeconds#
487                                                        seconds.
488                                                </li>
489                                                <cfelse>
490                                                        <li>The time it took to fill out the form did not fall within your
491                                                                configured threshold of #getConfig().timedFormMinSeconds#-#getConfig().timedFormMaxSeconds#
492                                                                seconds.  Also, I think the form data for this field was tampered with by the
493                                                                spammer.
494                                                        </li>
495                                                </cfif>
496                                        </cfif>
497                                       
498                                        <cfif StructKeyExists(arguments.TestResults,"hiddenFormField") AND NOT arguments.TestResults.hiddenFormField.Pass>
499                                        <li>The hidden form field that is supposed to be blank contained data.</li>
500                                        </cfif>
501                                       
502                                        <cfif StructKeyExists(arguments.TestResults,"SpamStrings") AND NOT arguments.TestResults.SpamStrings.Pass>
503                                        <li>One of the configured spam strings was found in the form submission.</li>
504                                        </cfif>
505                                       
506                                        <cfif StructKeyExists(arguments.TestResults,"akismet") AND NOT arguments.TestResults.akismet.Pass>
507                                                <!--- The next few lines build the URL to submit a false
508                                                                        positive notification to Akismet if this is not spam --->
509                                                <cfset falsePositiveURL = replace("#getConfig().akismetBlogURL#cfformprotect/akismetFailure.cfm?type=ham","://","^^","all")>
510                                                <cfset falsePositiveURL = replace(falsePositiveURL,"//","/","all")>
511                                                <cfset falsePositiveURL = replace(falsePositiveURL,"^^","://","all")>
512                                                <cfset falsePositiveURL = falsePositiveURL&"&user_ip=#urlEncodedFormat(cgi.remote_addr,'utf-8')#">
513                                                <cfset falsePositiveURL = falsePositiveURL&"&referrer=#urlEncodedFormat(cgi.http_referer,'utf-8')#">
514                                                <cfset falsePositiveURL = falsePositiveURL&"&comment_author=#urlEncodedFormat(form[getConfig().akismetFormNameField],'utf-8')#">
515                                                <cfif getConfig().akismetFormEmailField neq "">
516                                                <cfset falsePositiveURL = falsePositiveURL&"&comment_author_email=#urlEncodedFormat(form[getConfig().akismetFormEmailField],'utf-8')#">
517                                                </cfif>
518                                                <cfif getConfig().akismetFormURLField neq "">
519                                                <cfset falsePositiveURL = falsePositiveURL&"&comment_author_url=#urlEncodedFormat(form[getConfig().akismetFormURLField],'utf-8')#">
520                                                </cfif>
521                                                <cfset falsePositiveURL = falsePositiveURL&"&comment_content=#urlEncodedFormat(form[getConfig().akismetFormBodyField],'utf-8')#">
522                                                <li>Akisment thinks this is spam, if it's not please mark this as a
523                                                false positive by <cfoutput><a href="#falsePositiveURL#">clicking here</a></cfoutput>.</li>
524                                        <cfelseif StructKeyExists(arguments.TestResults,"akismet") AND arguments.TestResults.akismet.ValidKey AND arguments.TestResults.akismet.Pass>
525                                                <!--- The next few lines build the URL to submit a missed
526                                                                        spam notification to Akismet --->
527                                                <cfset missedSpamURL = replace("#getConfig().akismetBlogURL#cfformprotect/akismetFailure.cfm?type=spam","://","^^","all")>
528                                                <cfset missedSpamURL = replace(missedSpamURL,"//","/","all")>
529                                                <cfset missedSpamURL = replace(missedSpamURL,"^^","://","all")>
530                                                <cfset missedSpamURL = missedSpamURL&"&user_ip=#urlEncodedFormat(cgi.remote_addr,'utf-8')#">
531                                                <cfset missedSpamURL = missedSpamURL&"&referrer=#urlEncodedFormat(cgi.http_referer,'utf-8')#">
532                                                <cfset missedSpamURL = missedSpamURL&"&comment_author=#urlEncodedFormat(form[getConfig().akismetFormNameField],'utf-8')#">
533                                                <cfif getConfig().akismetFormEmailField neq "">
534                                                <cfset missedSpamURL = missedSpamURL&"&comment_author_email=#urlEncodedFormat(form[getConfig().akismetFormEmailField],'utf-8')#">
535                                                </cfif>
536                                                <cfif getConfig().akismetFormURLField neq "">
537                                                <cfset missedSpamURL = missedSpamURL&"&comment_author_url=#urlEncodedFormat(form[getConfig().akismetFormURLField],'utf-8')#">
538                                                </cfif>
539                                                <cfset missedSpamURL = missedSpamURL&"&comment_content=#urlEncodedFormat(form[getConfig().akismetFormBodyField],'utf-8')#">
540                                                Akismet did not think this message was spam.  If it was, please <a href="#missedSpamURL#">notify Akismet</a> that it
541                                                missed one.
542                                        </cfif>
543                                       
544                                        <cfif StructKeyExists(arguments.TestResults,"TooManyUrls") AND NOT arguments.TestResults.tooManyUrls.Pass>
545                                               <li>There were too many URLs in the form contents</li>
546                                        </cfif>
547                                       
548                                        <cfif StructKeyExists(arguments.TestResults,"ProjHoneyPot") AND NOT arguments.TestResults.ProjHoneyPot.Pass>
549                                        <li>The user's IP address has been flagged by Project Honey Pot.</li>
550                                        </cfif>
551                                       
552                                </ol>
553                                Failure score: #totalPoints#<br />
554                                Your failure threshold: #getConfig().failureLimit#
555                        <br /><br />
556                        IP address: #cgi.remote_addr#<br />
557                        User agent: #cgi.http_user_agent#<br />
558                        Previous page: #cgi.http_referer#<br />
559                        Form variables:
560                        <cfdump var="#form#">
561                </cfmail>
562        </cffunction>
563
564        <cffunction name="logFailure" acces="private" output="false" returntype="void">
565                <cfargument name="TestResults" required="true" type="struct" />
566                <cfargument name="FormStruct" required="true" type="struct">
567                <cfargument name="TotalPoints" required="true" type="numeric" />
568                <cfargument name="LogFile" required="true" type="string" />
569                <cfscript>
570                var falsePositiveURL = "";
571                var missedSpamURL = "";
572                var LogText = "Message marked as spam!   ";
573                </cfscript>
574       
575                <cfif StructKeyExists(arguments.TestResults,"mouseMovement") AND NOT arguments.TestResults.mouseMovement.Pass>
576                        <cfset LogText = LogText & "--- No mouse movement was detected." />
577                </cfif>
578                                       
579                <cfif StructKeyExists(arguments.TestResults,"usedKeyboard") AND NOT arguments.TestResults.usedKeyboard.Pass>
580                        <cfset LogText = LogText & "--- No keyboard activity was detected." />
581                </cfif>
582                                       
583                <cfif StructKeyExists(arguments.TestResults,"timedFormSubmission") AND NOT arguments.TestResults.timedFormSubmission.Pass>
584                        <cfif StructKeyExists(arguments.FormStruct,("formfield1234567893"))>
585                                <cfset LogText = LogText & "--- The time it took to fill out the form did not fall within your configured threshold of #getConfig().timedFormMinSeconds#-#getConfig().timedFormMaxSeconds# seconds." />
586                               
587                        <cfelse>
588                                <cfset LogText = LogText & "The time it took to fill out the form did not fall within your configured threshold of #getConfig().timedFormMinSeconds#-#getConfig().timedFormMaxSeconds# seconds.  Also, I think the form data for this field was tampered with by the spammer." />
589                        </cfif>
590                </cfif>
591                                       
592                <cfif StructKeyExists(arguments.TestResults,"hiddenFormField") AND NOT arguments.TestResults.hiddenFormField.Pass>
593                        <cfset LogText = LogText & "--- The hidden form field that is supposed to be blank contained data." />
594                </cfif>
595               
596                <cfif StructKeyExists(arguments.TestResults,"SpamStrings") AND NOT arguments.TestResults.SpamStrings.Pass>
597                        <cfset LogText = LogText & "--- One of the configured spam strings was found in the form submission." />
598                </cfif>
599                                       
600                <cfif StructKeyExists(arguments.TestResults,"akismet") AND NOT arguments.TestResults.akismet.Pass>
601                        <!--- The next few lines build the URL to submit a false
602                                                positive notification to Akismet if this is not spam --->
603                        <cfset falsePositiveURL = replace("#getConfig().akismetBlogURL#cfformprotect/akismetFailure.cfm?type=ham","://","^^","all")>
604                        <cfset falsePositiveURL = replace(falsePositiveURL,"//","/","all")>
605                        <cfset falsePositiveURL = replace(falsePositiveURL,"^^","://","all")>
606                        <cfset falsePositiveURL = falsePositiveURL&"&user_ip=#urlEncodedFormat(cgi.remote_addr,'utf-8')#">
607                        <cfset falsePositiveURL = falsePositiveURL&"&referrer=#urlEncodedFormat(cgi.http_referer,'utf-8')#">
608                        <cfset falsePositiveURL = falsePositiveURL&"&comment_author=#urlEncodedFormat(form[getConfig().akismetFormNameField],'utf-8')#">
609                        <cfif getConfig().akismetFormEmailField neq "">
610                                <cfset falsePositiveURL = falsePositiveURL&"&comment_author_email=#urlEncodedFormat(form[getConfig().akismetFormEmailField],'utf-8')#">
611                        </cfif>
612                        <cfif getConfig().akismetFormURLField neq "">
613                                <cfset falsePositiveURL = falsePositiveURL&"&comment_author_url=#urlEncodedFormat(form[getConfig().akismetFormURLField],'utf-8')#">
614                        </cfif>
615                        <cfset falsePositiveURL = falsePositiveURL&"&comment_content=#urlEncodedFormat(form[getConfig().akismetFormBodyField],'utf-8')#">
616                        <cfset LogText = LogText & "--- Akisment thinks this is spam, if it's not please mark this as a
617                                                        false positive by visiting: #falsePositiveURL#" />
618                <cfelseif StructKeyExists(arguments.TestResults,"akismet") AND arguments.TestResults.akismet.ValidKey AND arguments.TestResults.akismet.Pass>
619                        <!--- The next few lines build the URL to submit a missed
620                                                spam notification to Akismet --->
621                        <cfset missedSpamURL = replace("#getConfig().akismetBlogURL#cfformprotect/akismetFailure.cfm?type=spam","://","^^","all")>
622                        <cfset missedSpamURL = replace(missedSpamURL,"//","/","all")>
623                        <cfset missedSpamURL = replace(missedSpamURL,"^^","://","all")>
624                        <cfset missedSpamURL = missedSpamURL&"&user_ip=#urlEncodedFormat(cgi.remote_addr,'utf-8')#">
625                        <cfset missedSpamURL = missedSpamURL&"&referrer=#urlEncodedFormat(cgi.http_referer,'utf-8')#">
626                        <cfset missedSpamURL = missedSpamURL&"&comment_author=#urlEncodedFormat(form[getConfig().akismetFormNameField],'utf-8')#">
627                        <cfif getConfig().akismetFormEmailField neq "">
628                                <cfset missedSpamURL = missedSpamURL&"&comment_author_email=#urlEncodedFormat(form[getConfig().akismetFormEmailField],'utf-8')#">
629                        </cfif>
630                        <cfif getConfig().akismetFormURLField neq "">
631                                <cfset missedSpamURL = missedSpamURL&"&comment_author_url=#urlEncodedFormat(form[getConfig().akismetFormURLField],'utf-8')#">
632                        </cfif>
633                        <cfset missedSpamURL = missedSpamURL&"&comment_content=#urlEncodedFormat(form[getConfig().akismetFormBodyField],'utf-8')#">
634                        <cfset LogText = LogText & "--- Akismet did not think this message was spam.  If it was, please visit: #missedSpamURL#" />
635                </cfif>
636                                       
637                <cfif StructKeyExists(TestResults,"TooManyUrls") AND NOT arguments.TestResults.tooManyUrls.Pass>
638                      <cfset LogText = LogText & "--- There were too many URLs in the form contents." />
639                </cfif>
640                                       
641                <cfif StructKeyExists(TestResults,"ProjHoneyPot") AND NOT arguments.TestResults.ProjHoneyPot.Pass>
642                      <cfset LogText = LogText & "--- The user's IP address has been flagged by Project Honey Pot." />
643                </cfif>
644                                       
645                <cfset LogText = LogText & "--- Failure score: #totalPoints#.  Your failure threshold: #getConfig().failureLimit#.  IP address: #cgi.remote_addr#       User agent: #cgi.http_user_agent#       Previous page: #cgi.http_referer#" />
646       
647                <cflog file="#arguments.LogFile#" text="#LogText#" />
648        </cffunction>
649
650
651</cfcomponent>
652
Note: See TracBrowser for help on using the browser.