[dw-free] crossposter: don't save external passwords
[commit: http://hg.dwscoalition.org/dw-free/rev/3414d4ea320e]
http://bugs.dwscoalition.org/show_bug.cgi?id=959
Allow crossposter to prompt for passwords each post, so we don't save them
to the server.
Patch by
allen.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=959
Allow crossposter to prompt for passwords each post, so we don't save them
to the server.
Patch by
Files modified:
- bin/upgrading/en.dat
- cgi-bin/DW/External/XPostProtocol/LJXMLRPC.pm
- cgi-bin/weblib.pl
- htdocs/js/xpost.js
- htdocs/manage/externalaccount.bml
- htdocs/manage/externalaccount.bml.text
- htdocs/tools/endpoints/extacct_auth.bml
--------------------------------------------------------------------------------
diff -r f4777a2dc08a -r 3414d4ea320e bin/upgrading/en.dat
--- a/bin/upgrading/en.dat Mon Jan 04 19:37:22 2010 +0000
+++ b/bin/upgrading/en.dat Mon Jan 04 19:40:25 2010 +0000
@@ -4747,6 +4747,12 @@ xpost.error.invalidprotocol=Missing or i
xpost.notrespected=This will not respect your default <a [[aopts]]>crosspost settings</a>. Your crossposted entries will not be updated.
+xpost.nopw.cancel=Cancel
+
+xpost.nopw.checking=Getting authentication...
+
+xpost.nopw.required=Password required.
+
xpost.password=Password:
xpost.poll.view=View poll: [[name]]
diff -r f4777a2dc08a -r 3414d4ea320e cgi-bin/DW/External/XPostProtocol/LJXMLRPC.pm
--- a/cgi-bin/DW/External/XPostProtocol/LJXMLRPC.pm Mon Jan 04 19:37:22 2010 +0000
+++ b/cgi-bin/DW/External/XPostProtocol/LJXMLRPC.pm Mon Jan 04 19:40:25 2010 +0000
@@ -75,16 +75,34 @@ sub _call_xmlrpc {
# LJ-XMLRPC library class.
sub do_auth {
my ($self, $xmlrpc, $auth) = @_;
-
+
+ # if we've already set up an ljsession, just use it.
+ if ($auth->{ljsession}) {
+ return $auth;
+ }
+
# challenge/response for user validation
if ($auth->{auth_challenge} && $auth->{auth_response}) {
- # if we already have them, just return.
- return {
+ # if we already have a challenge and response, then do a login.
+
+ my $challengecall = $self->_call_xmlrpc($xmlrpc, "sessiongenerate", {
+ ver => 1,
+ auth_method => 'challenge',
username => $auth->{username},
auth_challenge => $auth->{auth_challenge},
- auth_response => $auth->{auth_response},
- success => 1
- };
+ auth_response => $auth->{auth_response},
+ expiration => 'short'
+ });
+
+ if ($challengecall->{success}) {
+ $auth->{success} = 1;
+ $auth->{ljsession} = $challengecall->{result}->{ljsession};
+ return $auth;
+ } else {
+ # just return the result hashref (with error)
+ return $challengecall;
+ }
+
} else {
my $challengecall = $self->_call_xmlrpc($xmlrpc, 'getchallenge', {});
if ($challengecall->{success}) {
@@ -125,14 +143,28 @@ sub call_xmlrpc {
return $authresp unless $authresp->{success};
# return the results of the call
- return $self->_call_xmlrpc($xmlrpc, $mode, {
- ver => 1,
- auth_method => 'challenge',
- username => $authresp->{username},
- auth_challenge => $authresp->{auth_challenge},
- auth_response => $authresp->{auth_response},
- %{ $req || {} }
- });
+ if ($authresp->{ljsession}) {
+ # do an ljsession login
+ $xmlrpc->transport->http_request->push_header('X-LJ-Auth', 'cookie');
+ $xmlrpc->transport->http_request->push_header( Cookie => "ljsession=" . $authresp->{ljsession} );
+
+ return $self->_call_xmlrpc($xmlrpc, $mode, {
+ ver => 1,
+ auth_method => 'cookie',
+ username => $authresp->{username},
+ %{ $req || {} }
+ });
+ } else {
+ # do a standalone challenge/response login.
+ return $self->_call_xmlrpc($xmlrpc, $mode, {
+ ver => 1,
+ auth_method => 'challenge',
+ username => $authresp->{username},
+ auth_challenge => $authresp->{auth_challenge},
+ auth_response => $authresp->{auth_response},
+ %{ $req || {} }
+ });
+ }
}
# does a crosspost using the LJ XML-RPC protocol. returns a hashref
diff -r f4777a2dc08a -r 3414d4ea320e cgi-bin/weblib.pl
--- a/cgi-bin/weblib.pl Mon Jan 04 19:37:22 2010 +0000
+++ b/cgi-bin/weblib.pl Mon Jan 04 19:40:25 2010 +0000
@@ -1274,7 +1274,7 @@ sub entry_form {
$out .= "<label for='usejournal' class='left'>" . BML::ml('entryform.postto') . "</label>\n";
$out .= LJ::html_select({ 'name' => 'usejournal', 'id' => 'usejournal', 'selected' => $usejournal,
'tabindex' => $tabindex->(), 'class' => 'select',
- "onchange" => "changeSubmit('".$submitprefix."','".$remote->{'user'}."'); getUserTags('$remote->{user}'); changeSecurityOptions('$remote->{user}'); LiveJournal.updateXpostFromJournal('$remote->{user}');" },
+ "onchange" => "changeSubmit('".$submitprefix."','".$remote->{'user'}."'); getUserTags('$remote->{user}'); changeSecurityOptions('$remote->{user}'); XPostAccount.updateXpostFromJournal('$remote->{user}');" },
"", $remote->{'user'},
map { $_, $_ } @{$res->{'usejournals'}}) . "\n";
$out .= "</p>\n";
@@ -1653,7 +1653,6 @@ MOODS
if ( $remote && ! $altlogin ) {
# crosspost
- $$onload .= " LiveJournal.updateXpostFromJournal('$remote->{user}');";
my @accounts = DW::External::Account->get_external_accounts($remote);
# populate the per-account html first, so that we only have to
@@ -1686,37 +1685,44 @@ MOODS
'value' => '1',
'selected' => $selected,
'tabindex' => $tabindex->(),
- 'onchange' => 'LiveJournal.xpostAcctUpdated();',
+ 'onchange' => 'XPostAccount.xpostAcctUpdated();',
}) . "</td>\n";
$xpostbydefault = 1 if $selected;
- # accounts with no password are disabled for now.
- #$accthtml .= "<td>";
- #unless ($acct->password) {
+ $accthtml .= "<td>";
+ unless ($acct->password) {
# password field if no password
- # $accthtml .= "<label for='prop_xpost_password_$acctid'>" . BML::ml('xpost.password') . "</label>";
- # $accthtml .= LJ::html_text({
- # 'name' => "prop_xpost_password_$acctid",
- # 'id' => "prop_xpost_password_$acctid",
- # 'value' => "",
- # 'disabled' => 0,
- # 'size' => 40,
- # 'maxlength' => 80,
- # 'type' => 'password'
- # });
- #}
- #$accthtml .= "</td>\n";
- # do a challenge/response if available.
- #my $challenge = eval { $acct->challenge; };
- #if ($challenge) {
- #$accthtml .= "<input type='hidden' name='prop_xpost_chal_$acctid' id='prop_xpost_chal_$acctid' class='xpost_chal' value='$challenge' />";
- #$accthtml .= "<input type='hidden' name='prop_xpost_chal_$acctid' id='prop_xpost_chal_$acctid' class='xpost_chal' value='$acctid' />";
- #$accthtml .= "<input type='hidden' name='prop_xpost_resp_$acctid' id='prop_xpost_resp_$acctid'/>";
- #}
+ $accthtml .= "<span id='prop_xpost_pwspan_$acctid'>";
+ $accthtml .= "<label for='prop_xpost_password_$acctid'>" . BML::ml('xpost.password') . "</label>";
+ $accthtml .= LJ::html_text({
+ 'name' => "prop_xpost_password_$acctid",
+ 'id' => "prop_xpost_password_$acctid",
+ 'value' => "",
+ 'disabled' => 0,
+ 'size' => 40,
+ 'maxlength' => 80,
+ 'type' => 'password',
+ 'class' => 'xpost_pw'
+ });
+ $accthtml .= "<span class='xpost_pwstatus' id='prop_xpost_pwstatus_$acctid'></span>";
+ $accthtml .= "<input type='hidden' name='prop_xpost_chal_$acctid' id='prop_xpost_chal_$acctid' class='xpost_chal' />";
+ $accthtml .= "<input type='hidden' name='prop_xpost_resp_$acctid' id='prop_xpost_resp_$acctid'/>";
+ $accthtml .= "</span>";
+ }
+ $accthtml .= "</td>\n";
+
$accthtml .= "</tr>\n";
}
}
-
+ $out .= qq [
+ <script type="text/javascript" language="JavaScript">
+ // xpost messages
+ var xpostUser = '$remote->{user}';
+ ];
+ $out .= "var xpostCheckingMessage = '" . BML::ml('xpost.nopw.checking') . "';\n";
+ $out .= "var xpostCancelLabel = '" . BML::ml('xpost.nopw.cancel') . "';\n";
+ $out .= "var xpostPwRequired = '" . BML::ml('xpost.nopw.required') . "';\n";
+ $out .= "</script>\n";
$out .= "<div id='xpostdiv'>\n";
$out .= "<p><label for='prop_xpost_check' class='left options'>" . BML::ml('entryform.xpost') . "</label>";
$out .= LJ::html_check({
@@ -1728,7 +1734,7 @@ MOODS
'selected' => $xpostbydefault,
'disabled' => (scalar @accounts) ? '0' : '1',
'tabindex' => $xpost_tabindex,
- 'onchange' => 'LiveJournal.xpostButtonUpdated();',
+ 'onchange' => 'XPostAccount.xpostButtonUpdated();',
});
$out .= LJ::help_icon_html('prop_xpost_check');
$out .= "<a href = '/manage/settings/?cat=othersites'>" . BML::ml('entryform.xpost.manage') . "</a>";
@@ -1737,11 +1743,7 @@ MOODS
$out .= "</table>\n";
$out .= "</div>\n";
- # disable choices if no xpost selected by default.
$out .= qq [
- <script type="text/javascript">
- LiveJournal.xpostAcctUpdated();
- </script>
<p class='pkg'>
<span class='inputgroup-left'></span>
];
@@ -1772,7 +1774,7 @@ PREVIEW
PREVIEW
}
if ($LJ::SPELLER && !$opts->{'disabled_save'}) {
- $out .= LJ::html_submit('action:spellcheck', BML::ml('entryform.spellcheck'), { 'tabindex' => $tabindex->() }) . " ";
+ $out .= LJ::html_submit('action:spellcheck', BML::ml('entryform.spellcheck'), { onclick => 'XPostAccount.doSpellcheck()', tabindex => $tabindex->() }) . " ";
}
# Update posting date/time
$out .= "<input type='button' value='" . BML::ml( 'entryform.updatedate' ) . "' onclick='settime(\"" . LJ::ejs( BML::ml( 'entryform.dateupdated' ) ) . "\", this);' tabindex='" . $tabindex->() . "' />";
@@ -1946,7 +1948,7 @@ PREVIEW
# do a double-confirm on delete if we have crossposts that
# would also get removed
- my $delete_onclick = "return LiveJournal.confirmDelete('" . LJ::ejs(BML::ml('entryform.delete.confirm')) . "', '" . LJ::ejs(BML::ml('entryform.delete.xposts.confirm')) . "')";
+ my $delete_onclick = "return XPostAccount.confirmDelete('" . LJ::ejs(BML::ml('entryform.delete.confirm')) . "', '" . LJ::ejs(BML::ml('entryform.delete.xposts.confirm')) . "')";
$out .= LJ::html_submit('action:delete', BML::ml('entryform.delete'), {
'disabled' => $opts->{'disabled_delete'},
'tabindex' => $tabindex->(),
diff -r f4777a2dc08a -r 3414d4ea320e htdocs/js/xpost.js
--- a/htdocs/js/xpost.js Mon Jan 04 19:37:22 2010 +0000
+++ b/htdocs/js/xpost.js Mon Jan 04 19:40:25 2010 +0000
@@ -1,46 +1,167 @@ LiveJournal.xpostButtonUpdated = functio
-LiveJournal.xpostButtonUpdated = function () {
- var xpost_button = document.getElementById("prop_xpost_check");
- var xpost_checkboxes = DOM.getElementsByTagAndClassName(document, "input", "xpost_acct_checkbox") || [];
- for (var i=0; i < xpost_checkboxes.length; i++) {
- xpost_checkboxes[i].disabled = ! xpost_button.checked;
+// class representing a crosspost account
+XPostAccount = new Class(Object, {
+ init: function (acctid) {
+ this.acctid = acctid;
+ this.checkboxTag = $("prop_xpost_" + acctid);
+ this.chalField = $("prop_xpost_chal_" + acctid);
+ this.statusField = $("prop_xpost_pwstatus_" + acctid);
+ this.respField = $("prop_xpost_resp_" + acctid);
+ this.passField = $("prop_xpost_password_" + acctid);
+ this.pwSpan = $("prop_xpost_pwspan_" + acctid);
+ DOM.addEventListener(this.checkboxTag, 'change', this.checkboxChanged.bindEventListener(this));
+ this.checkboxChanged();
+ this.clearSettings();
+ },
+
+ checkboxChanged: function(evt) {
+ if (this.passField != null) {
+ if (this.checkboxTag.checked) {
+ this.pwSpan.style.display='inline';
+ } else {
+ this.pwSpan.style.display='none';
+ }
+
+ }
+ },
+
+ setDisabled: function(disabled) {
+ this.checkboxTag.disabled = disabled;
+ if (this.passField != null) {
+ this.passField.disabled = disabled;
+ }
+ },
+
+ clearSettings: function () {
+ this.failed = false;
+ this.locked = false;
+ },
+
+ clearPassword: function () {
+ if (this.passField != null) {
+ this.passField.value = "";
+ }
+ },
+
+ doChallengeResponse: function () {
+ // check to see if we need to do a challenge/response for this.
+ if ((! this.locked) && this.chalField != null && this.checkboxTag != null && this.checkboxTag.checked) {
+ this.locked = true;
+
+ if (this.passField == null || this.passField.value == null || this.passField.value == "") {
+ this.setError(xpostPwRequired);
+ this.failed = true;
+ this.locked = false;
+ return;
+ }
+ this.setMessage(xpostCheckingMessage + "<input type='button' onclick='XPostAccount.cancelSubmit()' value='" + xpostCancelLabel + "'/>");
+
+ var opts = {
+ "async": true,
+ "method": "GET",
+ "url": window.parent.Site.siteroot + "/__rpc_extacct_auth?acctid=" + this.acctid,
+ "onError": this.gotError.bind(this),
+ "onData": this.gotInfo.bind(this)
+ };
+ window.parent.HTTPReq.getJSON(opts);
+ }
+ },
+
+ gotError: function (err) {
+ if (this.locked) {
+ this.setError(err);
+ this.failed = true;
+ this.locked = false;
+ XPostAccount.checkComplete();
+ }
+ return;
+ },
+
+ gotInfo: function (data) {
+ if (this.locked) {
+ if (data.error) {
+ this.setError(data.error);
+ this.failed = true;
+ this.locked = false;
+ XPostAccount.checkComplete();
+ return;
+ }
+
+ this.statusField.innerHTML = "";
+ if (!data.success) return;
+
+ var pass = this.passField.value;
+ var res = MD5(data.challenge + MD5(pass));
+ this.respField.value = res;
+ this.chalField.value = data.challenge;
+
+ this.failed = false;
+ this.locked = false;
+ XPostAccount.checkComplete();
+ }
+ },
+
+ setMessage: function(message) {
+ if (this.statusField != null) {
+ this.statusField.innerHTML=message;
+ }
+ },
+
+ setError: function(message) {
+ this.setMessage("<span style='color: red;'>" + message + "</span>");
+ }
+
+});
+
+XPostAccount.xpostButtonUpdated = function () {
+ var xpost_button = $("prop_xpost_check");
+ var allunchecked = true;
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
+ XPostAccount.accounts[i].setDisabled(! xpost_button.checked);
+ allunchecked = allunchecked && ! XPostAccount.accounts[i].checkboxTag.checked;
+ }
+ if (allunchecked && xpost_button.checked) {
+ for (var i=0; i < XPostAccount.accounts.length; i++) {
+ XPostAccount.accounts[i].checkboxTag.checked = true;
+ }
}
}
-LiveJournal.xpostAcctUpdated = function () {
- var xpost_button = document.getElementById("prop_xpost_check");
- var xpost_checkboxes = DOM.getElementsByTagAndClassName(document, "input", "xpost_acct_checkbox") || [];
+XPostAccount.xpostAcctUpdated = function () {
+ var xpost_button = $("prop_xpost_check");
var allunchecked = true;
- for (var i=0; i < xpost_checkboxes.length; i++) {
- allunchecked = allunchecked && ! xpost_checkboxes[i].checked;
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
+ allunchecked = allunchecked && ! XPostAccount.accounts[i].checkboxTag.checked;
}
xpost_button.checked = ! allunchecked;
xpost_button.disabled = allunchecked;
}
-LiveJournal.updateXpostFromJournal = function (user) {
+XPostAccount.updateXpostFromJournal = function (user) {
// only allow crossposts to the user's own journal
var journal = document.updateForm.usejournal.value;
var allowXpost = (journal == '' || user == journal);
- var xpost_button = document.getElementById("prop_xpost_check");
+ var xpost_button = $("prop_xpost_check");
// preserve existing disabled state if xpost allowed
- xpost_button.disabled = (! allowXpost) || xpost_button.disabled;
- var xpost_checkboxes = DOM.getElementsByTagAndClassName(document, "input", "xpost_acct_checkbox") || [];
- for (var i=0; i < xpost_checkboxes.length; i++) {
+ var allunchecked = true;
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
+ allunchecked = allunchecked && ! XPostAccount.accounts[i].checkboxTag.checked;
+ }
+ xpost_button.disabled = (! allowXpost || allunchecked);
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
// preserve existing disabled state if xpost allowed
- xpost_checkboxes[i].disabled = (! allowXpost) || xpost_checkboxes[i].disabled;
+ XPostAccount.accounts[i].setDisabled(! allowXpost || (! xpost_button.checked && ! allunchecked));
}
- var xpostdiv = document.getElementById('xpostdiv');
+ var xpostdiv = $('xpostdiv');
if (allowXpost) {
xpostdiv.style.display = 'block';
} else {
xpostdiv.style.display = 'none';
}
-
}
-LiveJournal.confirmDelete = function (confMessage, xpostConfMessage) {
+XPostAccount.confirmDelete = function (confMessage, xpostConfMessage) {
// basic confirm
var conf = confirm(confMessage);
if (conf) {
@@ -60,73 +181,101 @@ LiveJournal.confirmDelete = function (co
return conf;
}
-// NOTE: this functionality is disabled; for now, we're requiring passwords
-// for external accounts.
+XPostAccount.loadAccounts = function () {
+ XPostAccount.skipChecks = false;
+ XPostAccount.accounts = new Array();
+ var xpost_fields = DOM.getElementsByTagAndClassName(document, "input", "xpost_acct_checkbox") || [];
+ for (var i=0; i < xpost_fields.length; i++) {
+ XPostAccount.accounts[i] = new XPostAccount(xpost_fields[i].id.substring(11));
+ }
+}
-// add chal/resp auth to the "login" form if it exists
+// add chal/resp auth to the update form if it exists
// this requires md5.js
-LiveJournal.setUpXpostForm = function () {
+XPostAccount.setUpXpostForm = function () {
var updateForm = document.getElementById('updateForm');
- DOM.addEventListener(updateForm, "submit", LiveJournal.xpostFormSubmitted.bindEventListener(updateForm));
-
+ DOM.addEventListener(updateForm, "submit", XPostAccount.xpostFormSubmitted.bindEventListener(updateForm));
+ XPostAccount.loadAccounts();
+ XPostAccount.xpostAcctUpdated();
+ XPostAccount.updateXpostFromJournal(xpostUser);
}
// When the form is submitted, compute the challenge response and clear out the plaintext password field
-LiveJournal.xpostFormSubmitted = function (evt) {
+XPostAccount.xpostFormSubmitted = function (evt) {
var updateForm = evt.target;
+
if (! updateForm)
return true;
- var xpost_fields = DOM.getElementsByTagAndClassName(document, "input", "xpost_chal") || [];
- for (var i=0; i < xpost_fields.length; i++) {
- var chal_field = xpost_fields[i];
- if (chal_field.value != null && chal_field.value != "") {
- var acctid = chal_field.id.substring(16);
+ if (! XPostAccount.skipChecks) {
- var resp_field = document.getElementById("prop_xpost_resp_" + acctid);
- var pass_field = document.getElementById("prop_xpost_password_" + acctid);
+ $('formsubmit').disabled=true;
+ evt.preventDefault();
- if (chal_field && resp_field && pass_field) {
- //LiveJournal.getChallenge(username, acctid, resp_field, pass_field);
- }
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
+ XPostAccount.accounts[i].doChallengeResponse();
+ }
+
+ XPostAccount.checkComplete();
+ }
+}
+
+XPostAccount.checkComplete = function() {
+ // check to see if all of our accounts are complete
+ for (var i=0; i < XPostAccount.accounts.length; i++) {
+ if (XPostAccount.accounts[i].locked) {
+ return false;
}
}
+
+ // all complete; see if there's an error.
+ var acctErr = false;
+ for (var i=0; i < XPostAccount.accounts.length; i++) {
+ if (XPostAccount.accounts[i].failed) {
+ acctErr = true;
+ }
+ }
+
+ if (acctErr) {
+ XPostAccount.doCancel();
+ } else {
+ XPostAccount.doFormSubmit();
+ }
+}
+
+// called when a user manually aborts an auth request attempt.
+XPostAccount.cancelSubmit = function() {
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
+ XPostAccount.accounts[i].setMessage("");
+ }
+ XPostAccount.doCancel();
+}
+
+// cancels the submit attempt; called either when the user hits cancel,
+// or when one of the auth challenge requests fails
+XPostAccount.doCancel = function() {
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
+ XPostAccount.accounts[i].clearSettings();
+ }
+ $('formsubmit').disabled=false;
+}
+
+XPostAccount.doSpellcheck = function() {
+ XPostAccount.skipChecks = true;
+}
+
+// does the actual form submit after all ofthe validation and auth requests
+// have taken place
+XPostAccount.doFormSubmit = function() {
+ var updateForm = document.getElementById('updateForm');
+ updateForm.onsubmit = null;
+ // clear out the pw fields.
+ for (var i = 0; i < XPostAccount.accounts.length; i++) {
+ XPostAccount.accounts[i].clearPassword();
+ }
+ updateForm.submit();
+
return false;
}
-LiveJournal.getChallenge = function(username, acctid, resp_field, pass_field) {
-
- var url = window.parent.Site.siteroot + "/__rpc_extacct_auth?username=" + username + "&acctid=" + acctid;
-
- var gotError = function(err) {
- alert(err+' '+username);
- return;
- }
-
- var gotInfo = function (data) {
- if (data.error) {
- alert(data.error + ' ' + username);
- return;
- }
-
- if (!data.success) return;
-
- var pass = pass_field.value;
- var res = MD5(data.challenge + MD5(pass));
- resp_field.value = res;
- pass_field.value = ""; // dont send clear-text password!
- }
-
- var opts = {
- "async": false,
- "method": "GET",
- "url": url,
- "onError": gotError,
- "onData": gotInfo
- };
-
- window.parent.HTTPReq.getJSON(opts);
-}
-
-// disabled for now.
-//LiveJournal.register_hook("page_load", LiveJournal.setUpXpostForm);
+LiveJournal.register_hook("page_load", XPostAccount.setUpXpostForm);
diff -r f4777a2dc08a -r 3414d4ea320e htdocs/manage/externalaccount.bml
--- a/htdocs/manage/externalaccount.bml Mon Jan 04 19:37:22 2010 +0000
+++ b/htdocs/manage/externalaccount.bml Mon Jan 04 19:40:25 2010 +0000
@@ -191,9 +191,22 @@ use strict;
selected => $editpage ? $editacct->xpostbydefault : $POST{xpostbydefault}
});
my $xpostbydefault_errdiv = errdiv(\%errs, "xpostbydefault");
- $body .= "<br />$xpostbydefault_errdiv" if $xpostbydefault_errdiv;
- $body .= "</td></tr>\n";
+ $body .= "<br />$xpostbydefault_errdiv" if $xpostbydefault_errdiv;
+ $body .= "</td></tr>\n";
+ $body .= "<tr><td class='setting_label'><label for='savepassword'>" . $ML{'.setting.xpost.option.savepassword'} . "</label></td>";
+ $body .= "<td>" . LJ::html_check({
+ name => "savepassword",
+ value => 1,
+ id => "savepassword",
+ selected => LJ::did_post() ?
+ $POST{savepassword} :
+ $editpage ? $editacct->password ne "" : 1,
+ });
+ my $savepassword_errdiv = errdiv(\%errs, "savepassword");
+ $body .= "<br />$savepassword_errdiv" if $savepassword_errdiv;
+ $body .= "</td></tr>\n";
+
$body .= "<tr><td>";
$body .= "<br />";
$body .= LJ::html_submit(undef, $editpage ? $ML{'.btn.update'} : $ML{'.btn.create'});
@@ -238,6 +251,7 @@ sub create_external_account {
$opts{password} = $POST->{password};
$opts{username} = $POST->{username};
$opts{xpostbydefault} = $POST->{xpostbydefault};
+ $opts{savepassword} = $POST->{savepassword};
# username is required
if (! $opts{username}) {
@@ -245,12 +259,6 @@ sub create_external_account {
$ok = 0;
}
- # password is required, at least for now.
- if (! $opts{password}) {
- $errs->{password} = BML::ml('.settings.xpost.error.password.required');
- $ok = 0;
- }
-
# check if it's a default site or a custom site
if ($POST->{"site"} ne -1) {
# default site; just use the siteid
@@ -304,6 +312,10 @@ sub create_external_account {
}
if ($ok) {
+ # if the user requested that we don't save their password, then
+ # don't save their password.
+ $opts{password} = "" if $opts{savepassword};
+
my $new_acct = DW::External::Account->create($u, \%opts);
# FIXME add error if create fails.
if ($new_acct) {
@@ -358,14 +370,11 @@ sub edit_external_account {
my $acct = DW::External::Account->get_external_account($u, $POST{acctid});
return 0 unless $acct;
- # password is required, at least for now.
- if (! $POST{password}) {
- $errs->{password} = BML::ml('.settings.xpost.error.password.required');
- return 0;
- }
-
my $newpw = $POST{password} || "";
- if ($POST{password} ne "__passwd__") {
+ if (! $POST{savepassword}) {
+ # don't save the password.
+ $acct->set_password("");
+ } elsif ($POST{password} ne "__passwd__") {
# we have a password
$acct->set_password($POST{password});
}
diff -r f4777a2dc08a -r 3414d4ea320e htdocs/manage/externalaccount.bml.text
--- a/htdocs/manage/externalaccount.bml.text Mon Jan 04 19:37:22 2010 +0000
+++ b/htdocs/manage/externalaccount.bml.text Mon Jan 04 19:40:25 2010 +0000
@@ -32,6 +32,8 @@
.setting.xpost.option.password.info=(Please make sure you have caps-lock disabled and enter the correct password.)
+.setting.xpost.option.savepassword=Save Password
+
.setting.xpost.option.servicename=Custom Service Name
.setting.xpost.option.servicetype=Custom Service Type
diff -r f4777a2dc08a -r 3414d4ea320e htdocs/tools/endpoints/extacct_auth.bml
--- a/htdocs/tools/endpoints/extacct_auth.bml Mon Jan 04 19:37:22 2010 +0000
+++ b/htdocs/tools/endpoints/extacct_auth.bml Mon Jan 04 19:40:25 2010 +0000
@@ -4,8 +4,6 @@
use vars qw(%GET);
use JSON;
use DW::External::Account;
-
- # FIXME: this functionality has not been enabled yet.
# error method
my $err = sub {
@@ -19,9 +17,6 @@
BML::set_content_type('text/javascript; charset=utf-8');
BML::finish();
- # annotate this isn't used yet, just in case
- return $err->( 'This functionality has not been enabled yet.' );
-
# get user
my $u = LJ::get_remote()
or return $err->(BML::ml('/tools/endpoints/extacct_auth.bml.error.nouser'));
@@ -36,7 +31,7 @@
# get the auth challenge
my $challenge = $account->challenge;
- return $err->BML::ml('/tools/endpoints/extacct_auth.bml.error.nosuchaccount', { account => $account->displayname } ) unless $challenge;
+ return $err->(BML::ml('/tools/endpoints/extacct_auth.bml.error.authfailed', { account => $account->displayname } )) unless $challenge;
# return the challenge
return LJ::js_dumper( { challenge => $challenge, success => 1 } );
--------------------------------------------------------------------------------
