Home | History | Annotate | Download | only in web
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "WebPasswordFormData.h"
     33 
     34 #include "HTMLNames.h"
     35 #include "core/dom/Document.h"
     36 #include "core/html/HTMLFormElement.h"
     37 #include "core/html/HTMLInputElement.h"
     38 #include "platform/weborigin/KURL.h"
     39 
     40 #include "DOMUtilitiesPrivate.h"
     41 #include "WebPasswordFormUtils.h"
     42 
     43 using namespace WebCore;
     44 
     45 namespace blink {
     46 
     47 namespace {
     48 
     49 // Helper to determine which password is the main one, and which is
     50 // an old password (e.g on a "make new password" form), if any.
     51 bool locateSpecificPasswords(PasswordFormFields* fields,
     52                              HTMLInputElement** password,
     53                              HTMLInputElement** oldPassword)
     54 {
     55     ASSERT(fields);
     56     ASSERT(password);
     57     ASSERT(oldPassword);
     58     switch (fields->passwords.size()) {
     59     case 1:
     60         // Single password, easy.
     61         *password = fields->passwords[0];
     62         break;
     63     case 2:
     64         if (fields->passwords[0]->value() == fields->passwords[1]->value())
     65             // Treat two identical passwords as a single password.
     66             *password = fields->passwords[0];
     67         else {
     68             // Assume first is old password, second is new (no choice but to guess).
     69             *oldPassword = fields->passwords[0];
     70             *password = fields->passwords[1];
     71         }
     72         break;
     73     case 3:
     74         if (fields->passwords[0]->value() == fields->passwords[1]->value()
     75             && fields->passwords[0]->value() == fields->passwords[2]->value()) {
     76             // All three passwords the same? Just treat as one and hope.
     77             *password = fields->passwords[0];
     78         } else if (fields->passwords[0]->value() == fields->passwords[1]->value()) {
     79             // Two the same and one different -> old password is duplicated one.
     80             *oldPassword = fields->passwords[0];
     81             *password = fields->passwords[2];
     82         } else if (fields->passwords[1]->value() == fields->passwords[2]->value()) {
     83             *oldPassword = fields->passwords[0];
     84             *password = fields->passwords[1];
     85         } else {
     86             // Three different passwords, or first and last match with middle
     87             // different. No idea which is which, so no luck.
     88             return false;
     89         }
     90         break;
     91     default:
     92         return false;
     93     }
     94     return true;
     95 }
     96 
     97 // Helped method to clear url of unneeded parts.
     98 KURL stripURL(const KURL& url)
     99 {
    100     KURL strippedURL = url;
    101     strippedURL.setUser(String());
    102     strippedURL.setPass(String());
    103     strippedURL.setQuery(String());
    104     strippedURL.setFragmentIdentifier(String());
    105     return strippedURL;
    106 }
    107 
    108 WebString getElementNameOrId(const HTMLInputElement& element)
    109 {
    110     return element.nameForAutofill();
    111 }
    112 
    113 // Helper to gather up the final form data and create a PasswordForm.
    114 void assemblePasswordFormResult(const KURL& fullOrigin,
    115                                 const KURL& fullAction,
    116                                 HTMLFormControlElement* submit,
    117                                 HTMLInputElement* userName,
    118                                 const Vector<String>& alternateUserNames,
    119                                 HTMLInputElement* oldPassword,
    120                                 HTMLInputElement* password,
    121                                 WebPasswordFormData* result)
    122 {
    123     // We want to keep the path but strip any authentication data, as well as
    124     // query and ref portions of URL, for the form action and form origin.
    125     result->action = stripURL(fullAction);
    126     result->origin = stripURL(fullOrigin);
    127 
    128     // Naming is confusing here because we have both the HTML form origin URL
    129     // the page where the form was seen), and the "origin" components of the url
    130     // (scheme, host, and port).
    131     KURL signonRealmURL = stripURL(fullOrigin);
    132     signonRealmURL.setPath("");
    133     result->signonRealm = signonRealmURL;
    134 
    135     result->possibleUserNames = alternateUserNames;
    136     if (submit)
    137         result->submitElement = submit->name();
    138     if (userName) {
    139         result->userNameElement = getElementNameOrId(*userName);
    140         result->userNameValue = userName->value();
    141     }
    142     if (password) {
    143         result->passwordElement = getElementNameOrId(*password);
    144         result->passwordValue = password->value();
    145         result->passwordShouldAutocomplete = password->shouldAutocomplete();
    146     }
    147     if (oldPassword) {
    148         result->oldPasswordElement = getElementNameOrId(*oldPassword);
    149         result->oldPasswordValue = oldPassword->value();
    150     }
    151 }
    152 
    153 } // namespace
    154 
    155 WebPasswordFormData::WebPasswordFormData(const WebFormElement& webForm)
    156 {
    157     RefPtr<HTMLFormElement> form = webForm.operator PassRefPtr<HTMLFormElement>();
    158     PasswordFormFields fields;
    159     findPasswordFormFields(form.get(), &fields);
    160 
    161     // Get the document URL
    162     KURL fullOrigin(ParsedURLString, form->document().documentURI());
    163 
    164     // Calculate the canonical action URL
    165     String action = form->action();
    166     if (action.isNull())
    167         action = ""; // missing 'action' attribute implies current URL
    168     KURL fullAction = form->document().completeURL(action);
    169     if (!fullAction.isValid())
    170         return;
    171 
    172     // Determine the types of the password fields
    173     HTMLInputElement* password = 0;
    174     HTMLInputElement* oldPassword = 0;
    175     if (!locateSpecificPasswords(&fields, &password, &oldPassword))
    176         return;
    177 
    178     assemblePasswordFormResult(fullOrigin, fullAction,
    179                                fields.submit, fields.userName,
    180                                fields.alternateUserNames,
    181                                oldPassword, password, this);
    182 }
    183 
    184 } // namespace blink
    185