My applet basically takes lots of different user input, stores it, and displays it back to the user in various ways and allows the user to do stuff with it. Apart from Shane Stanley’s excellent Myriad Tables Lib, it doesn’t use AppleScript Objective C.
so far I’ve never really bothered validating user input, except for the basics like coercing numbers to numbers and ensuring they are within the expected range and coercing dates to date values and, in some cases, ensuring text entered is of a particular length or not more than one word. I’ve got a relatively small user base and have had no issues so far.
But as I’m in the process of rewriting my applet I’m planning to do more. I’m writing a generic handler for my library which will allow me to get and validate user input. At the moment it allows me to do all the basic stuff as above.
Should I be worried about any particular characters? I thought I’d probably blacklist the tab character as that shouldn’t be necessary and may make displaying the data wonky, and I’ll make allowing the return character optional. I feel I should probably disallow backslash and quote for good measure, though the way AppleScript handles these appears to be pretty safe. Are there any other characters I should be worried about?
My other option would be to whitelist which characters are allowed and just include upper and lower case letters, digits, and the handful of special characters I think would be relevant.
Most of the resources on this general topic are of course concerned with preventing code injection. I’m not sure if that’s something I need to be concerned about but if it’s a possibility and I can prevent it then why not.
for anyone who’s interested, my code is below.
on returnOBValue given prompt:thePrompt as text : "Please enter a number.", defaultValue:theValue : "", valueType:classOfValueToReturn : "", minValue:minValue as number : missing value, maxValue:maxValue as number : missing value, errorStringIfTooLow:errorStringIfTooLow as text : missing value, errorStringIfTooHigh:errorStringIfTooHigh as text : missing value, negativesAllowed:negativesAllowed as boolean : false, zeroAllowed:zeroAllowed as boolean : false, title:thisTitle as text : missing value, stepCount:theStep as integer : 0, backButtonName:backButtonName as text : "Back", nextButtonName:nextButtonName as text : "Next", emptyStringAllowed:emptyStringAllowed as boolean : false, spacesAllowed:spacesAllowed as boolean : true, multipleWordsAllowed:multipleWordsAllowed as boolean : true, listOfProhibitedCharacters:prohibitedCharacters as list : {}, multipleParagraphsAllowed:multipleParagraphsAllowed as boolean : false
set prohibitedCharacters to prohibitedCharacters & {"/", "<", ">", "{", "}", "@", tab, return, "\\", "\""}
if minValue is not missing value and errorStringIfTooLow is missing value then set errorStringIfTooLow to "The number you entered is too low. You may not enter a number lower than " & minValue & "."
if maxValue is not missing value and errorStringIfTooHigh is missing value then set errorStringIfTooHigh to "The number you entered is too high. You may not enter a number greater than " & maxValue & "."
set userCancelled to false
set msg to ""
repeat
try
if thisTitle is missing value then
set dialogResult to (display dialog msg & thePrompt default answer theValue buttons {"Cancel", backButtonName, nextButtonName} cancel button 1 default button 3 with icon note)
else
set dialogResult to (display dialog msg & thePrompt default answer theValue with title thisTitle buttons {"Cancel", backButtonName, nextButtonName} cancel button 1 default button 3 with icon note)
end if
on error number -128
set userCancelled to true
exit repeat
end try
set theValue to text returned of dialogResult
if button returned of dialogResult is nextButtonName then
try
if emptyStringAllowed is false and theValue is "" then error "sorry, this field is mandatory. You must enter something in it to proceed." & return & return
-- if the returned value is to be a number and the text entered has a "$" then remove it
if (class of classOfValueToReturn is integer or class of classOfValueToReturn is real) then
if the first character of theValue is "$" then set theValue to (characters 2 through -1 of theValue) as text
try
set theValue to theValue as number
end try
-- ensure the value is the required class
if class of classOfValueToReturn is integer and class of theValue is not integer then error "You must enter a whole number." & return & return
if class of classOfValueToReturn is real and class of theValue is integer then
set theValue to theValue as real
else if class of classOfValueToReturn is real and class of theValue is not real then
error "You must enter a number." & return & return
end if
if negativesAllowed is false and theValue is less than 0 then error "You may not enter a negative amount." & return & return
if zeroAllowed is false and theValue is 0 then error "The amount cannot be 0. If it is, what's the point? 😕" & return & return
if minValue is not missing value and theValue is less than minValue then error errorStringIfTooLow & return & return
if maxValue is not missing value and theValue is greater than maxValue then error errorStringIfTooHigh & return & return
else -- required class is not a number
if maxValue is not missing value and (count of characters in theValue) is greater than maxValue then error "That's too many characters. The maximum number of characters you may enter is " & maxValue & "." & return & return
if minValue is not missing value and (count of characters in theValue) is less than minValue then error "You must enter at least " & minValue & " characters." & return & return
if spacesAllowed is false and theValue contains space then error "You may not enter spaces." & return & return
if multipleWordsAllowed is false and (count of words in theValue) is greater than 1 then error "You may only enter one word." & return & return
if multipleParagraphsAllowed is false and theValue contains linefeed then error "Multiple paragraphs are not permitted." & return & return
repeat with theCharacter in prohibitedCharacters
if theValue contains theCharacter then
-- if the prohibited character is whitespace, then we need to give special attention to the error message
if theCharacter is space then
error "Sorry, spaces are not permitted." & return & return
else if theCharacter is tab then
error "Sorry, tab characters are not permitted." & return & return
else if theCharacter is linefeed then
error "Sorry, new lines are not permitted." & return & return
else if theCharacter is return then
error "Sorry, carriage returns/multiple paragraphs are not permitted." & return & return
else
error "Sorry, “" & theCharacter & "” is a prohibited character." & return & return
end if
end if
end repeat
end if
set theStep to theStep + 1
exit repeat
on error msg
end try
else -- user chose back
set theStep to theStep - 1
exit repeat
end if
end repeat
return {userCancelled:userCancelled, stepCount:theStep, valueReturned:theValue}
end returnOBValue