####################################################################### ## The Registration Template Configuration ####################################################################### ## ## Constants: ## These are defined in other places around XWiki, changing them here will result in undefined behavior. #set($redirectParam = "xredirect") #set($userSpace = "XWiki.") #set($loginPage = "XWiki.XWikiLogin") ## ## Return the given password in the html code in case the user got a field wrong the password will ## still be filled in. Also the user can click a button to log in after they register. ## Disabling this will make the password never be returned in HTML. #set($returnPassword = true) ## ## Use javascript based live validation see: http://www.livevalidation.com #set($useLiveValidation = true) $xwiki.get("ssx").use("XWiki.LiveValidationExtension") $xwiki.get("jsx").use("XWiki.LiveValidationExtension") ## ## Defines what server generated error messages should look like ## The error message when a field is entered incorrectly #set($failureMessageParams = {'style' : 'color:#C00; font-weight:bold; margin:0 0 0 5px;'}) ## The * next to the fields to denote they are mandatory. #set($fieldMandatoryStar = $failureMessageParams) ## ## Client side javascript regex name validation. ## Escaped version of: ^[^<>\'\"\\x5C]*$ blocks < > ' " \ characters #set($jsNameRegex = '"+unescape("%5E%5B%5E%3C%3E%27%22%5Cx5C%5D*%24")+"') ## Equivilant expression for server side testing. #set($serverSideNameRegex = '/^[^<>\"\x27\\]*$/') #* * The fields which will be seen on the registration page are defined here. * $fields is an array and each field is a Map. The names shown below are Map keys. * * Each field must have: * name - this is the name of the field, it will be the value for "name" and "id" * * Each field may have: * prompt - this String will be written above the field. * tag - the HTML tag which will be created, default is , may also be a non form tag such as * params - a Map, each key value pair will be in the html tag. eg: {"size" : "30"} becomes ' \" \\ " } } }) #set($discard = $fields.add($field)) ## ## The last name field, mandatory and checked for disallowed characters. #set($field = {"name" : "register_last_name", "prompt" : $msg.get('core.register.lastName'), "params" : { "type" : "text", "size" : "30" }, "validate" : { "mandatory" : { "failureMessage" : $msg.get('core.register.fieldMandatory') }, "regex" : { "pattern" : $serverSideNameRegex, "failureMessage" : "$msg.get('core.register.youCantUseCharacters') < > ' " \", "jsPattern" : $jsNameRegex, "jsFailureMessage" : "$msg.get('core.register.youCantUseCharacters') < > ' \" \\ " } } }) #set($discard = $fields.add($field)) ## ## The user name field, mandatory and programmatically checked to make sure the username doesn't exist. #set($field = {"name" : "xwikiname", "prompt" : $msg.get('core.register.username'), "params" : { "type" : "text", "onfocus" : "prepareName(document.forms.register);", "size" : "20" }, "validate" : { "mandatory" : { "failureMessage" : $msg.get('core.register.fieldMandatory') }, "programmaticValidation" : { "code" : "#nameAvailable($request.get('xwikiname'))", "failureMessage" : $msg.get('core.register.userAlreadyExists') } } }) #set($discard = $fields.add($field)) ## Make sure the chosen user name is not already taken ## This macro is called by programmaticValidation for xwikiname (above) #macro(nameAvailable, $name) #if($xwiki.exists("$userSpace$name")) failed #end #end ## ##The password field, mandatory. #set($field = {"name" : "register_password", "prompt" : $msg.get('core.register.password'), "params" : { "type" : "password", "size" : "10" }, "validate" : { "mandatory" : { "failureMessage" : $msg.get('core.register.fieldMandatory') } } }) #set($discard = $fields.add($field)) ## ##The confirm password field, mandatory and must match password field. #set($field = {"name" : "register2_password", "prompt" : $msg.get('core.register.passwordRepeat'), "params" : { "type" : "password", "size" : "10" }, "validate" : { "mandatory" : { "failureMessage" : $msg.get('core.register.fieldMandatory') }, "mustMatch" : { "name" : "register_password", "failureMessage" : $msg.get('core.register.passwordMismatch') } } }) #set($discard = $fields.add($field)) ## ## The email address field, mandatory and regex checked with an email pattern. #set($field = {"name" : "register_email", "prompt" : $msg.get('core.register.email'), "params" : { "type" : "text", "size" : "30" }, "validate" : { "mandatory" : { "failureMessage" : $msg.get('core.register.fieldMandatory') }, "regex" : { "jsPattern" : '^([^@\\s]+)@((?:[-a-zA-Z0-9]+\\.)+[a-zA-Z]{2,})$', "pattern" : '/^([^@\s]+)@((?:[-a-zA-Z0-9]+\.)+[a-zA-Z]{2,})$/', "failureMessage" : $msg.get('core.register.invalidEmail') } } }) #set($discard = $fields.add($field)) ## #* ## Uncomment this code to see an example of how you can easily add a field to the registration page ## Note: The user's favorite color is not saved anywhere, see above for information on how to save it. #set($field = {"name" : "favorite_color", "prompt" : "What is your favorite color", "params" : { "type" : "text", "size" : "30" }, "validate" : { "mandatory" : { "failureMessage" : $msg.get('core.register.fieldMandatory') }, "regex" : { "pattern" : "green", "failureMessage" : "You are not cool enough to register here." } } }) #set($discard = $fields.add($field)) ## *# ## To disable the captcha on this page, comment out the next two entries. ## The captcha image, not an input field but still defined the same way. #if($captchaservice && $captchaservice.isEnabled()) ## Empty prompt field used for padding. #set($field = {"name" : "captcha_image", "prompt" : "", "tag" : "img", "params" : { "src" : "$doc.getURL('imagecaptcha')", "alt" : "$msg.get('core.captcha.image.alternateText', [$msg.get('core.register.submit')])" } }) #set($discard = $fields.add($field)) ## The captcha field #set($field = {"name" : "captcha_answer", "prompt" : $msg.get('core.captcha.image.instruction'), "params" : { "type" : "text", "size" : "30" }, "validate" : { "mandatory" : { "failureMessage" : $msg.get('core.register.fieldMandatory') }, "programmaticValidation" : { "code" : "#checkCaptcha($request, $request.get('captcha_answer'))", "failureMessage" : "$msg.get('core.captcha.captchaAnswerIsWrong')" } } }) #set($discard = $fields.add($field)) #end ## ## Checks the captcha answer; used by programmaticValidation above. #macro(checkCaptcha, $request, $answer) #set($cv = $captchaservice.getCaptchaVerifier("image")) #if(!$cv.isAnswerCorrect($cv.getUserId($request), $answer)) failed #end #end ## ## ####################################################################### ## The Code. ####################################################################### ## ## If the submit button has been pressed, then we test the input and maybe create the user. #if($request.getParameter("xwikiname")) ## Do server side validation of input fields. #set($discard = "#validateFields($fields, $request)") ## If server side validation was successfull, create the user #if(!$registrationFailed) #createUser($request, $response) #end #end ## If the registration was not successful or if the user hasn't submitted the info yet ## Then we display the registration form. #if(!$registrationDone) #generateRegistrationForm($fields, $fieldMandatoryStar, $failureMessageParams) #end ## ## The Macros (nothing below this point is run directly) ## #* * Server side validation, this is necessary for security and because not everyone has Javascript * * @param $fields The array of fields to validate. * @param $request An XWikiRequest object which made the register request, used to get parameters. *# #macro(validateFields, $fields, $request) #foreach($field in $fields) #if($field.get("validate") && $field.get("name")) #set($fieldName = $field.get("name")) #set($validate = $field.get("validate")) #set($error = "") #if($request.get($fieldName) && $request.get($fieldName) != "") #set($value = $request.get($fieldName)) ## ## Regex validation #if($validate.get("regex")) #set($regex = $validate.get("regex")) #if($regex.get("pattern") && $regex.get("failureMessage")) #if(!$xcontext.getUtil().match($regex.get("pattern"), $value)) #set($error = $regex.get("failureMessage")) #end #elseif($regex.get("pattern")) ERROR: In field: ${fieldName}: regex validation must include failureMessage. #end #end ## ## If regex validation passed, check "mustMatch" validation #if($error == "" && $validate.get("mustMatch")) #set($mustMatch = $validate.get("mustMatch")) #if($mustMatch.get("name") && $mustMatch.get("failureMessage")) #if($request.get($fieldName) != $request.get($mustMatch.get("name"))) #set($error = $mustMatch.get("failureMessage")) #end #else ERROR: In field: ${fieldName}: mustMatch validation required both name (of field which this field must match) and failureMessage. #end #end ## ## If regex and mustMatch validation passed, try programmatic validation #if($error == "" && $validate.get("programmaticValidation")) #set($pv = $validate.get("programmaticValidation")) #if($pv.get("code") && $pv.get("failureMessage")) #set($pvReturn = "#evaluate($pv.get('code'))") #if($pvReturn.indexOf("failed") != -1) #set($error = $pv.get("failureMessage")) #end #else ERROR: In field: ${fieldName}: programmaticValidation requires code and failureMessage #end #end ## ## If no content, check if content is mandatory #elseif($validate.get("mandatory")) #set($mandatory = $validate.get("mandatory")) #if($mandatory.get("failureMessage")) #set($error = $mandatory.get("failureMessage")) #else ERROR: In field: ${fieldName}: mandatory validation requires a failureMessage #end #end #if($error != "") #set($discard = $field.put("error", $error)) #set($registrationFailed = true) #end #elseif(!$field.get("name")) ERROR: Field with no name. #end##if(validate) #end##loop #end##macro ## ## #* * Create the user. * Calls $xwiki.createUser to create a new user. * * @param $request An XWikiRequest object which made the register request. * @param $response The XWikiResponse object to send any redirects to. *# #macro(createUser, $request, $response) ## See if email verification is required and register the user. #if($xwiki.getXWikiPreferenceAsInt("use_email_verification", 0) == 1) #set($reg = $xwiki.createUser(true)) #else #set($reg = $xwiki.createUser(false)) #end ## ## Handle output from the registration. #if($reg && $reg <= 0) #if($reg == -2) #error($msg.get('core.register.passwordMismatch')) ## -3 means username taken, -8 means username is superadmin name #elseif($reg == -3 || $reg == -8) #error($msg.get('core.register.userAlreadyExists')) #elseif($reg == -4) #error($msg.get('core.register.invalidUsername')) #else #error($msg.get('core.register.registerFailed', [$reg])) #end #elseif($reg) ## Registration was successful #set($registrationDone = true) #set($xwname = "$userSpace${request.xwikiname}") #info($msg.get('core.register.successful', [$xwiki.getUserName($xwname), $request.xwikiname])) ## ## Give the user a login button which posts their username and password to loginsubmit #if($returnPassword) #blockXSS()
#else ## ## Send a redirect if one was sent to us. #set($redirect = $request.getParameter($redirectParam)) #if($redirect) $response.sendRedirect($redirect); #end ## #end #end ## #end## createUser Macro ## ## #* * Generate registration form. * Here we generate the actual HTML and Javascript code for the registration form. * * @param $fields The array of fields to put in the form. * @param $fieldMandatoryStar The tag parameters for a * indicating a mandatory field. * @param $failureMessageParams The tag parameters for a failure message. *# #macro(generateRegistrationForm, $fields, $fieldMandatoryStar, $failureMessageParams) #define($output) #generateHtml($fields, $fieldMandatoryStar, $failureMessageParams) #if($useLiveValidation) #generateJavascript($fields) #end #end ## Remove whitespace from the beginnings of lines to make HTML reading easier for smaller output. $xcontext.getUtil().getP5util().substitute('s/(\n)\s+/$1/g', "$output") #end ## ## #* * Generate HTML form, this is the only place where HTML is written. * * @param $fields The array of fields to use for generating html code. * @param $fieldMandatoryStar The tag parameters for a * indicating a mandatory field. * @param $failureMessageParams The tag parameters for a failure message. *# #macro(generateHtml, $fields, $fieldMandatoryStar, $failureMessageParams) #define($html) ## Put the same values back into the fields. #getParams($fields) ##
## #foreach($field in $fields) #if($field.get("name")) #set($fieldName = $field.get("name")) #if($field.get("prompt")) #set($prompt = $field.get("prompt"))
$prompt #if($field.get("validate").get("mandatory")) * #end
#end ## If no tag then default tag is #if($field.get("tag")) #set($tag = $field.get("tag")) #else #set($tag = "input") #end
<$tag id="$fieldName" name="$fieldName" #if($field.get("params")) #set($params = $field.get("params")) #foreach($entry in $params.entrySet()) $entry.getKey()="$entry.getValue()" #end #end value="$!field.get('value')" /> #if($field.get("error")) $field.get("error") #end
#else ERROR: Field with no name. #end##if fieldName exists #end
#end ## ## Remove newlines inside of tags because tags are generated by loops. $xcontext.getUtil().getP5util().substitute('s/([^>\s]+)\s+/$1 /g', "$html") #end ## ## #* * Generate the Javascript for interacting with LiveValidation. * * @param $fields The array of fields which to validate. *# #macro(generateJavascript, $fields) #end##macro ## ## #* * Get parameters from request so that values will be filled in if there is a mistake * in one of the entries. * * @param $fields The array of fields to get parameters for. *# #macro(getParams $fields) #blockXSS() #foreach($field in $fields) #if($field.get("name") && $request.get($field.get("name"))) #if($returnPassword || !$field.get("params") || $field.get("params").get("type") != "password") #set($discard = $field.put("value", $request.get($field.get("name")))) #end #end #end #end ## ## #* * Block XSS * * We must prevent non-persistent XSS by not getting parameters if the request is not a post * or if the referer header is not this page. * Imagine a link such as .../XWiki/Register?register_first_name= *# #macro(blockXSS) #if($request.getParameterMap().size() > 0) #if($request.getHeader("referer") != $xwiki.getRequestURL() || $request.getMethod() != "POST") ## If there is a redirect to send after registration is over, preserve it. #set($redirect = $request.getParameter($redirectParam)) #if($redirect) ## There is a redirect parameter, if that is not the only parameter, then send a redirect with that as the only param #if($request.getParameterMap().size() > 1) $response.sendRedirect("$request.getRequestURI()?$!redirectParam=$!redirect") #end #else ## There is no redirect parameter, no parameters are acceptable. $response.sendRedirect($request.getRequestURI()) #end #end #end #end