head<= <=head body<= " unless LJ::text_in(\%POST); my $mode = $POST{'mode'}; my $code = $POST{'code'} || $GET{'code'}; if ($LJ::USE_SSL && ! $LJ::IS_SSL && $FORM{'ssl'} ne "no") { return BML::redirect("$LJ::SSLROOT/create.bml"); } # with no mode, decide which screen the user sees first, based # on whether or not this LJ installation lets in free users if ($mode eq "") { $mode = $LJ::USE_ACCT_CODES ? ($code ? "codesubmit" : "entercode") : "getinfo"; } my $remote = LJ::get_remote(); my %errors; my $error_msg = sub { my $key = shift; my $pre = shift; my $post = shift; my $msg = $errors{$key}; return unless $msg; return "$pre $msg $post"; }; # Flag to indicate they've submitted with 'audio' as the answer to the spambot # challenge. my $wants_audio = 0; # Captcha my $recaptcha = Captcha::reCAPTCHA->new; # validate a code they've entered and throw them back to entercode # mode if it's invalid if ($code && $mode eq "submit" || # account codes turned off, but one specified anyway $LJ::USE_ACCT_CODES && ($mode eq "codesubmit" || $mode eq "submit")) # account codes required { my $error; my $userid = 0; # acceptable userid for double-click protection if ($mode eq "submit") { my $u = LJ::load_user($POST{'user'}); $userid = $u->{'userid'}; } $errors{'code'} = $error unless (LJ::acct_code_check($code, \$error, $userid)); if (%errors) { $mode = "entercode"; } elsif ($mode eq "codesubmit") { $mode = "getinfo"; } } # MODE: entercode - enter an account code to proceed making an account if ($LJ::USE_ACCT_CODES && $mode eq "entercode") { my $ret; my $v; $ret .= "
\n"; $ret .= LJ::html_hidden(mode => 'codesubmit', ssl => $FORM{'ssl'}); $ret .= ""; $v = LJ::ehtml($code); $ret .= " "; $ret .= $error_msg->('code', '
'); $ret .= " standout?>"; $ret .= "
\n"; open (REM, "$LJ::HOME/htdocs/inc/account-codes"); while () { $ret .= $_; } close REM; return $ret; } # MODE: submit - if they've given 'audio' as the answer to the spambot-blocker, # reset the mode to 'getinfo' and set the audio flag if ( $LJ::HUMAN_CHECK{create} && $mode eq 'submit' && lc($POST{answer}) eq 'audio' ) { $mode = 'getinfo'; $wants_audio = 1; } # MODE: submit - try to create an account. might change mode # if there are errors, we'll populate %errors and # return to "getinfo" mode below SUBMIT: while ($mode eq "submit") # using while instead of if so we can 'last' out of it { return "$ML{'Error'}: $ML{'.error.postrequired'}" unless LJ::did_post(); my $user = LJ::canonical_username($POST{'user'}); my $email = LJ::trim(lc($POST{'email'})); # setup global things that can be used to modify the user later my $is_underage = 0; # turn on if the user should be marked as underage my $ofage = 0; # turn on to note that the user is over 13 in actuality # (but is_underage might be on which just means that their # account is being marked as underage--even if they're old # enough [unique cookie check]) # reject this email? return LJ::sysban_block(0, "Create user blocked based on email", { 'new_user' => $user, 'email' => $email, 'name' => $user }) if LJ::sysban_check('email', $email); my $dbh = LJ::get_db_writer(); if (length($user) > 15) { $errors{'username'} = "$ML{'error.usernamelong'}"; } if ($POST{'user'} && ! $user) { $errors{'username'} = "$ML{'error.usernameinvalid'}"; } unless ($POST{'user'}) { $errors{'username'} = "$ML{'.error.username.mustenter'}"; } foreach my $re ("^system\$", @LJ::PROTECTED_USERNAMES) { next unless ($user =~ /$re/); # you can give people sharedjournal priv ahead of time to create # reserved communities: next if LJ::check_priv($remote, "sharedjournal", $user); $errors{'username'} = "$ML{'.error.username.reserved'}"; } # see if they're confused and entered a valid account code # for their username (happens often) if ($LJ::USE_ACCT_CODES && $user =~ /^.....a[ab].....$/) { # see if the acctcode is valid and unused my ($acid, $auth) = LJ::acct_code_decode($user); my $is_valid = $dbh->selectrow_array("SELECT COUNT(*) FROM acctcode ". "WHERE acid=? AND rcptid=0", undef, $acid); $errors{'username'} = "$ML{'.error.username.iscode'}" if $is_valid; } my $u = LJ::load_user($user); my $second_submit = 0; if ($u) { my $in_use = 1; if ($u->{'email'} eq $POST{'email'}) { if (LJ::login_ip_banned($u)) { # brute-force possible going on } else { if ($u->{'password'} eq $POST{'password1'}) { # oh, they double-clicked the submit button $second_submit = 1; $in_use = 0; } else { LJ::handle_bad_login($u); } } } if ($in_use) { $errors{'username'} = "$ML{'.error.username.inuse'}"; } } $POST{'password1'} = LJ::trim($POST{'password1'}); $POST{'password2'} = LJ::trim($POST{'password2'}); if ($POST{'password1'} ne $POST{'password2'}) { $errors{'password'} = "$ML{'.error.password.nomatch'}"; } else { my @checkpass = LJ::run_hooks("bad_password", { 'user' => $user, 'name' => $user, 'email' => $email, 'password' => $POST{'password1'} }); if (@checkpass && $checkpass[0]->[0]) { $errors{'password'} = "Bad password: $checkpass[0]->[0]"; } } if (! $POST{'password1'}) { $errors{'password'} = "$ML{'.error.password.blank'}"; } elsif (length $POST{'password1'} > 30) { $errors{'password'} = "$ML{'password.max30'}"; } unless (LJ::is_ascii($POST{'password1'})) { $errors{'password'} = "$ML{'.error.password.asciionly'}"; } ### start COPPA_CHECK # age checking to determine how old they are if ($LJ::COPPA_CHECK) { my $uniq; if ($LJ::UNIQ_COOKIES) { $uniq = Apache->request->notes('uniq'); if ($uniq) { my $timeof = $dbh->selectrow_array('SELECT timeof FROM underage WHERE uniq = ?', undef, $uniq); $is_underage = 1 if $timeof && $timeof > 0; } } my ($year, $mon, $day) = ( $POST{"bday_yyyy"}+0, $POST{"bday_mm"}+0, $POST{"bday_dd"}+0 ); if ($year < 100) { $POST{'bday_yyyy'} += 1900; $year += 1900; } # get current time my ($nday, $nmon, $nyear) = (gmtime())[3, 4, 5]; $nyear += 1900; $nmon += 1; # require dates in the 1900s (or beyond) if ($year && $mon && $day && $year >= 1900 && $year <= $nyear) { # now see how many years back they are my $ofageyear = $year + 13; if ($ofageyear > $nyear) { $is_underage = 1; } elsif ($ofageyear == $nyear) { # years match, see if they were born after this month if ($mon > $nmon) { $is_underage = 1; } elsif ($mon == $nmon) { # now check the day if ($day > $nday) { $is_underage = 1; } else { $ofage = 1; } } else { $ofage = 1; } } else { $ofage = 1; } } else { $errors{'bday'} = "$ML{'.error.birthday.invalid'}"; } # note this unique cookie as underage (if we have a unique cookie) if ($is_underage && $uniq) { $dbh->do("REPLACE INTO underage (uniq, timeof) VALUES (?, UNIX_TIMESTAMP())", undef, $uniq); } } ### end COPPA_CHECK if ($LJ::TOS_CHECK && ! $POST{'agree_tos'}) { $errors{'agree_tos'} = $ML{'tos.error'}; } # check the email address { my @email_errors; LJ::check_email($email, \@email_errors); if ($LJ::USER_EMAIL and $email =~ /\@\Q$LJ::USER_DOMAIN\E$/i) { push @email_errors, BML::ml(".error.email.lj_domain", {domain => $LJ::USER_DOMAIN}); } $errors{'email'} = join(", ", @email_errors) if @email_errors; } # Check the turing test answer if it's turned on if ($LJ::HUMAN_CHECK{create}) { my $result = $recaptcha->check_answer($LJ::recaptcha_private_key, LJ::get_remote_ip(), $POST{recaptcha_challenge_field}, $POST{recaptcha_response_field}); $errors{'captcha'} = $ML{'.captcha.invalid'} unless $result->{is_valid}; } if ($LJ::LJR_NEWACC_RATE && $LJ::LJR_NEWACC_RATEPERIOD) { my $numaccs = $dbh->selectrow_array( "SELECT count(*) FROM userlog WHERE ip = ? and action = 'account_create' and logtime > UNIX_TIMESTAMP() - ?", undef, LJ::get_remote_ip(), $LJ::LJR_NEWACC_RATEPERIOD); if ($numaccs > $LJ::LJR_NEWACC_RATE) { $errors{'banned'} = 'Sorry, we do not accept that much accounts from one person that fast.'; } } use Golem; my $tnet = Golem::get_containing_net(LJ::get_remote_ip(), {"with_props" => 1}); $tnet = Golem::get_net(LJ::get_remote_ip(), 32, {"with_props" => 1}) unless $tnet; if ($tnet && $tnet->{'props'}->{'data'}->{'ban_new_accounts'}) { $errors{'banned'} = 'Sorry, we do not accept accounts from you.'; } last SUBMIT if %errors; my $clusterid = ($LJ::ALLOW_CLUSTER_SELECT ? $POST{'cluster_id'} : LJ::new_account_cluster()) + 0; die "Cluster 0 not supported" unless $clusterid; my $userid = $u ? $u->{'userid'}+0 : 0; unless ($second_submit) { my $caps = int($LJ::NEWUSER_CAPS); my $status = ($LJ::EVERYONE_VALID ? 'A' : 'N'); my $errorcounter = 0; my $old_print_error = $dbh->{PrintError}; # save PrintError mode $dbh->{PrintError} = 0; # will check for errors manually while (1) { my $ruserid = LJ::get_new_userid("P"); if (!$ruserid) { return ""; } $dbh->do("set insert_id = $ruserid"); $dbh->do( "INSERT INTO user (user, email, password, status, caps, name, clusterid, dversion) ". "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", undef, $user, $email, $POST{'password1'}, $status, $caps, $user, $clusterid, $LJ::MAX_DVERSION); if ($dbh->err) { # who wants to try forever if ($errorcounter > 10) { return "" . $dbh->errstr . " p?>"; } $errorcounter++; sleep 1; # let it breathe next; # try again } else { $userid = $dbh->{'mysql_insertid'}; # smells like success $dbh->{PrintError} = $old_print_error; # restore error reporting return 0 unless $userid; # but? last; # finally } } if ($LJ::LJR_FIF) { use LJ::MemCache; my $ljr_fif_id = LJ::get_userid($LJ::LJR_FIF); if ($ljr_fif_id) { $dbh->do("INSERT INTO friends (userid, friendid) VALUES (?, ?)", undef, $ljr_fif_id, $userid); # refresh memcache #my $memkey = [$ljr_fif_id, "friends:$ljr_fif_id"]; #LJ::MemCache::delete($memkey); LJ::get_friends($ljr_fif_id, undef, undef, 'force', {} ); } } $dbh->do("REPLACE INTO useridmap (userid, user) VALUES (?, ?)", undef, $userid, $user); $dbh->do("REPLACE INTO userusage (userid, timecreate) VALUES (?, NOW())", undef, $userid); # if we're using account codes on this site, mark the code as used if ($code) { my ($acid, $auth) = LJ::acct_code_decode($code); $dbh->do("UPDATE acctcode SET rcptid=$userid WHERE acid=$acid"); if ($dbh->err) { return $dbh->errstr; } } # if we have initial friends for new accounts, add them. foreach my $friend (@LJ::INITIAL_FRIENDS) { my $friendid = LJ::get_userid($friend); LJ::add_friend($userid, $friendid) if $friendid; } foreach my $friend (@LJ::INITIAL_OPTIONAL_FRIENDS) { my $friendid = LJ::get_userid($friend); LJ::add_friend($userid, $friendid) if $friendid and $POST{"initial_optional_friend_$friend"}; } # Set any properties that get set in new users while (my ($name, $val) = each %LJ::USERPROP_INIT) { LJ::set_userprop($userid, $name, $val); } LJ::run_hooks("post_create", { 'userid' => $userid, 'user' => $user, 'code' => $code, }); } # send welcome mail... unless they're underage unless ($is_underage) { my $aa = {}; if ($userid) { $aa = LJ::register_authaction($userid, "validateemail", $email); } my $body = BML::ml('email.newacct2.body', { "email" => $email, "regurl" => "$LJ::SITEROOT/confirm/$aa->{'aaid'}.$aa->{'authcode'}", "username" => $user, "sitename" => $LJ::SITENAME, "siteroot" => $LJ::SITEROOT, "admin_email" => $LJ::ADMIN_EMAIL, "bogus_email" => $LJ::BOGUS_EMAIL, }); LJ::send_mail({ 'to' => $email, 'from' => $LJ::ADMIN_EMAIL, 'fromname' => $LJ::SITENAME, 'charset' => 'utf-8', 'subject' => BML::ml('email.newacct.subject', {'sitename' => $LJ::SITENAME}), 'body' => $body, }); } my $nu = LJ::load_userid($userid, "force"); # now flag as underage (and set O to mean was old or Y to mean was young) $nu->underage(1, $ofage ? 'O' : 'Y', 'account creation') if $is_underage; if ($LJ::TOS_CHECK) { my $err = ""; $nu->tosagree_set(\$err) or return LJ::bad_input($err); } # record create information $nu->log_event('account_create', { remote => $remote }); $nu->make_login_session; # local sites may want to override what happens at this point my $redirect = undef; my $stop_output; LJ::run_hooks("create.bml_postsession", { post => \%POST, u => $nu, redirect => \$redirect, ret => \$ret, stop_output => \$stop_output, }); return BML::redirect($redirect) if $redirect; return $ret if $stop_output; $ret = " $email, 'username' => $user}) ." p?>"; my $uri = LJ::journal_base($nu); $ret .= "\n"; $ret .= "$uri/ standout?>\n"; $ret .= "\n"; $ret .= "
"; $ret .= "

" . LJ::html_submit(undef, "$ML{'.success.btn.enterinfo'} →") . "

"; $ret .= "
\n"; return $ret; } if ($mode eq "getinfo" || %errors) { my $ret; my $v; if (%errors) { my @errors_order = ('code', 'username', 'email', 'password', 'agree_tos', 'captcha'); my %errors_def; $errors_def{$_} = 1 for @errors_order; foreach my $key (keys %errors) { push @errors_order, $key unless $errors_def{$key}; } $ret .= "$ML{'.errors.label'} standout?>"; } $ret .= "" unless %errors; $ret .= "
\n"; $ret .= LJ::html_hidden(mode => 'submit', code => $code, ssl => $FORM{'ssl'}); $ret .= "
    "; ### username $v = LJ::ehtml($FORM{'user'}); $ret .= "
  1. $ML{'.username.box.head'}
    "; $ret .= $error_msg->('username', '

    ', '

    '); $ret .= "
    " . BML::ml(".username.text", {'sitename' => $LJ::SITENAME}) . "
    "; $ret .= LJ::html_text({'name' => 'user', 'size' => 15, 'maxlength' => 15, 'value' => $v, raw => 'style=""' }); $ret .= "
    " . BML::ml('.community', { aopts => "href='$LJ::SITEROOT/community/create.bml'" }); $ret .= "
    $ML{'.username.charsallowed'}
    " if (!%errors || exists $errors{'username'}); $ret .= "
  2. "; ### email address $v = LJ::ehtml($FORM{'email'}); $ret .= "
  3. $ML{'.email.input.head'}
    "; $ret .= $error_msg->('email', '

    ', '

    '); $ret .= "
    " . BML::ml('.email.text3', { aopts => "target='_new' href='$LJ::SITEROOT/privacy.bml'", }) . "
    "; $ret .= LJ::html_text({'name' => 'email', 'size' => 40, 'maxlength' => 50, 'value' => $v,}); $ret .= "
  4. "; $ret .= "
  5. $ML{'.password.input.head1'}
    "; $ret .= $error_msg->('password', '

    ', '

    '); $ret .= "
    $ML{'.password.secure'}
    " if exists $errors{'password'}; $ret .= "
    $ML{'.password.text'}
    "; my $pass_value = $errors{'password'} ? "" : $POST{'password1'}; $ret .= LJ::html_text({'name' => 'password1', 'size' => 30, 'maxlength' => 31, 'type' => "password", value => $pass_value, }); $ret .= "
    $ML{'.password.input.head2'}
    "; $ret .= LJ::html_text({'name' => 'password2', 'size' => 30, 'maxlength' => 31, 'type' => "password", value => $pass_value, }); $ret .= "
  6. "; if (@LJ::INITIAL_OPTIONAL_FRIENDS) { $ret .= "
  7. $ML{'.initialfriends.heading'}
    "; $ret .= "
    $ML{'.initialfriends'}
    "; $ret .= "
    "; foreach my $friend (@LJ::INITIAL_OPTIONAL_FRIENDS) { $ret .= LJ::html_check({'name' => "initial_optional_friend_$friend", 'value' => 1, 'selected' => $POST{"initial_optional_friend_$friend"}, 'id' => "optfriend_$friend", }); $ret .= "
    "; } $ret .= "
  8. "; } if ($LJ::COPPA_CHECK) { $ret .= "
  9. $ML{'.birthday.head'}
    "; $ret .= "
    $errors{'bday'}
    " if exists $errors{'bday'}; $ret .= "
    $ML{'.birthday.question'}
    "; $ret .= ""; $ret .= "
    $ML{'.birthday.birthdate'}"; $ret .= LJ::html_datetime({ name => 'bday', notime => 1, default => sprintf("%04d-%02d-%02d", $POST{bday_yyyy}, $POST{bday_mm}, $POST{bday_dd}) }); $ret .= "$ML{'.birthday.required'}
  10. "; } LJ::run_hooks("create.bml_opts", { post => \%POST, get => \%GET, ret => \$ret, }); if ($LJ::TOS_CHECK) { $ret .= "
  11. $ML{'.tos.heading'}
    "; $ret .= LJ::tosagree_widget($POST{agree_tos}, $errors->{agree_tos}); $ret .= "
  12. "; } if ($LJ::ALLOW_CLUSTER_SELECT) { $ret .= "
  13. $ML{'.clusterselect.head'}
    "; $ret .= "
    $ML{'.clusterselect.text'}
    "; $ret .= LJ::html_select({ 'name' => 'cluster_id' }, "0", "$BML{'.clusterselect.nocluster'}", map { $_, BML::ml(".clusterselect.clusternum", {'number' => $_}) } @LJ::CLUSTERS); $ret .= "
    $ML{'.clusterselect.cluster'}
    "; $ret .= "
  14. "; } if ($LJ::HUMAN_CHECK{create}) { $ret .= "
  15. $ML{'.captcha.prove'}
    "; $ret .= $recaptcha->get_html($LJ::recaptcha_public_key); } $ret .= "
"; $ret .= "
"; $ret .= ""; $ret .= "
"; $ret .= "
"; return $ret; } return "$ML{'error.unknownmode'}: $mode"; _code?> <=body page?> link: htdocs/privacy.bml post: htdocs/create.bml, htdocs/editinfo.bml file: htdocs/inc/account-codes hook: post_create _c?>