Home | History | Annotate | Download | only in export
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.wizards.export;
     18 
     19 import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
     20 import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage;
     21 
     22 import org.eclipse.core.resources.IProject;
     23 import org.eclipse.jface.wizard.IWizardPage;
     24 import org.eclipse.swt.SWT;
     25 import org.eclipse.swt.events.ModifyEvent;
     26 import org.eclipse.swt.events.ModifyListener;
     27 import org.eclipse.swt.events.VerifyEvent;
     28 import org.eclipse.swt.events.VerifyListener;
     29 import org.eclipse.swt.layout.GridData;
     30 import org.eclipse.swt.layout.GridLayout;
     31 import org.eclipse.swt.widgets.Composite;
     32 import org.eclipse.swt.widgets.Label;
     33 import org.eclipse.swt.widgets.Text;
     34 
     35 import java.util.List;
     36 
     37 /**
     38  * Key creation page.
     39  */
     40 final class KeyCreationPage extends ExportWizardPage {
     41 
     42     private final ExportWizard mWizard;
     43     private Text mAlias;
     44     private Text mKeyPassword;
     45     private Text mKeyPassword2;
     46     private Text mCnField;
     47     private boolean mDisableOnChange = false;
     48     private Text mOuField;
     49     private Text mOField;
     50     private Text mLField;
     51     private Text mStField;
     52     private Text mCField;
     53     private String mDName;
     54     private int mValidity = 0;
     55     private List<String> mExistingAliases;
     56 
     57 
     58     protected KeyCreationPage(ExportWizard wizard, String pageName) {
     59         super(pageName);
     60         mWizard = wizard;
     61 
     62         setTitle("Key Creation");
     63         setDescription(""); // TODO?
     64     }
     65 
     66     @Override
     67     public void createControl(Composite parent) {
     68         Composite composite = new Composite(parent, SWT.NULL);
     69         composite.setLayoutData(new GridData(GridData.FILL_BOTH));
     70         GridLayout gl = new GridLayout(2, false);
     71         composite.setLayout(gl);
     72 
     73         GridData gd;
     74 
     75         new Label(composite, SWT.NONE).setText("Alias:");
     76         mAlias = new Text(composite, SWT.BORDER);
     77         mAlias.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
     78 
     79         new Label(composite, SWT.NONE).setText("Password:");
     80         mKeyPassword = new Text(composite, SWT.BORDER | SWT.PASSWORD);
     81         mKeyPassword.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
     82         mKeyPassword.addVerifyListener(sPasswordVerifier);
     83 
     84         new Label(composite, SWT.NONE).setText("Confirm:");
     85         mKeyPassword2 = new Text(composite, SWT.BORDER | SWT.PASSWORD);
     86         mKeyPassword2.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
     87         mKeyPassword2.addVerifyListener(sPasswordVerifier);
     88 
     89         new Label(composite, SWT.NONE).setText("Validity (years):");
     90         final Text validityText = new Text(composite, SWT.BORDER);
     91         validityText.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
     92         validityText.addVerifyListener(new VerifyListener() {
     93             @Override
     94             public void verifyText(VerifyEvent e) {
     95                 // check for digit only.
     96                 for (int i = 0 ; i < e.text.length(); i++) {
     97                     char letter = e.text.charAt(i);
     98                     if (letter < '0' || letter > '9') {
     99                         e.doit = false;
    100                         return;
    101                     }
    102                 }
    103             }
    104         });
    105 
    106         new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL).setLayoutData(
    107                 gd = new GridData(GridData.FILL_HORIZONTAL));
    108         gd.horizontalSpan = 2;
    109 
    110         new Label(composite, SWT.NONE).setText("First and Last Name:");
    111         mCnField = new Text(composite, SWT.BORDER);
    112         mCnField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
    113 
    114         new Label(composite, SWT.NONE).setText("Organizational Unit:");
    115         mOuField = new Text(composite, SWT.BORDER);
    116         mOuField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
    117 
    118         new Label(composite, SWT.NONE).setText("Organization:");
    119         mOField = new Text(composite, SWT.BORDER);
    120         mOField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
    121 
    122         new Label(composite, SWT.NONE).setText("City or Locality:");
    123         mLField = new Text(composite, SWT.BORDER);
    124         mLField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
    125 
    126         new Label(composite, SWT.NONE).setText("State or Province:");
    127         mStField = new Text(composite, SWT.BORDER);
    128         mStField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
    129 
    130         new Label(composite, SWT.NONE).setText("Country Code (XX):");
    131         mCField = new Text(composite, SWT.BORDER);
    132         mCField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
    133 
    134         // Show description the first time
    135         setErrorMessage(null);
    136         setMessage(null);
    137         setControl(composite);
    138 
    139         mAlias.addModifyListener(new ModifyListener() {
    140             @Override
    141             public void modifyText(ModifyEvent e) {
    142                 mWizard.setKeyAlias(mAlias.getText().trim());
    143                 onChange();
    144             }
    145         });
    146         mKeyPassword.addModifyListener(new ModifyListener() {
    147             @Override
    148             public void modifyText(ModifyEvent e) {
    149                 mWizard.setKeyPassword(mKeyPassword.getText());
    150                 onChange();
    151             }
    152         });
    153         mKeyPassword2.addModifyListener(new ModifyListener() {
    154             @Override
    155             public void modifyText(ModifyEvent e) {
    156                 onChange();
    157             }
    158         });
    159 
    160         validityText.addModifyListener(new ModifyListener() {
    161             @Override
    162             public void modifyText(ModifyEvent e) {
    163                 try {
    164                     mValidity = Integer.parseInt(validityText.getText());
    165                 } catch (NumberFormatException e2) {
    166                     // this should only happen if the text field is empty due to the verifyListener.
    167                     mValidity = 0;
    168                 }
    169                 mWizard.setValidity(mValidity);
    170                 onChange();
    171             }
    172         });
    173 
    174         ModifyListener dNameListener = new ModifyListener() {
    175             @Override
    176             public void modifyText(ModifyEvent e) {
    177                 onDNameChange();
    178             }
    179         };
    180 
    181         mCnField.addModifyListener(dNameListener);
    182         mOuField.addModifyListener(dNameListener);
    183         mOField.addModifyListener(dNameListener);
    184         mLField.addModifyListener(dNameListener);
    185         mStField.addModifyListener(dNameListener);
    186         mCField.addModifyListener(dNameListener);
    187     }
    188 
    189     @Override
    190     void onShow() {
    191         // fill the texts with information loaded from the project.
    192         if ((mProjectDataChanged & (DATA_PROJECT | DATA_KEYSTORE)) != 0) {
    193             // reset the keystore/alias from the content of the project
    194             IProject project = mWizard.getProject();
    195 
    196             // disable onChange for now. we'll call it once at the end.
    197             mDisableOnChange = true;
    198 
    199             String alias = ProjectHelper.loadStringProperty(project, ExportWizard.PROPERTY_ALIAS);
    200             if (alias != null) {
    201                 mAlias.setText(alias);
    202             }
    203 
    204             // get the existing list of keys if applicable
    205             if (mWizard.getKeyCreationMode()) {
    206                 mExistingAliases = mWizard.getExistingAliases();
    207             } else {
    208                 mExistingAliases = null;
    209             }
    210 
    211             // reset the passwords
    212             mKeyPassword.setText(""); //$NON-NLS-1$
    213             mKeyPassword2.setText(""); //$NON-NLS-1$
    214 
    215             // enable onChange, and call it to display errors and enable/disable pageCompleted.
    216             mDisableOnChange = false;
    217             onChange();
    218         }
    219     }
    220 
    221     @Override
    222     public IWizardPage getPreviousPage() {
    223         if (mWizard.getKeyCreationMode()) { // this means we create a key from an existing store
    224             return mWizard.getKeySelectionPage();
    225         }
    226 
    227         return mWizard.getKeystoreSelectionPage();
    228     }
    229 
    230     @Override
    231     public IWizardPage getNextPage() {
    232         return mWizard.getKeyCheckPage();
    233     }
    234 
    235     /**
    236      * Handles changes and update the error message and calls {@link #setPageComplete(boolean)}.
    237      */
    238     private void onChange() {
    239         if (mDisableOnChange) {
    240             return;
    241         }
    242 
    243         setErrorMessage(null);
    244         setMessage(null);
    245 
    246         if (mAlias.getText().trim().length() == 0) {
    247             setErrorMessage("Enter key alias.");
    248             setPageComplete(false);
    249             return;
    250         } else if (mExistingAliases != null) {
    251             // we cannot use indexOf, because we need to do a case-insensitive check
    252             String keyAlias = mAlias.getText().trim();
    253             for (String alias : mExistingAliases) {
    254                 if (alias.equalsIgnoreCase(keyAlias)) {
    255                     setErrorMessage("Key alias already exists in keystore.");
    256                     setPageComplete(false);
    257                     return;
    258                 }
    259             }
    260         }
    261 
    262         String value = mKeyPassword.getText();
    263         if (value.length() == 0) {
    264             setErrorMessage("Enter key password.");
    265             setPageComplete(false);
    266             return;
    267         } else if (value.length() < 6) {
    268             setErrorMessage("Key password is too short - must be at least 6 characters.");
    269             setPageComplete(false);
    270             return;
    271         }
    272 
    273         if (value.equals(mKeyPassword2.getText()) == false) {
    274             setErrorMessage("Key passwords don't match.");
    275             setPageComplete(false);
    276             return;
    277         }
    278 
    279         if (mValidity == 0) {
    280             setErrorMessage("Key certificate validity is required.");
    281             setPageComplete(false);
    282             return;
    283         } else if (mValidity < 25) {
    284             setMessage("A 25 year certificate validity is recommended.", WARNING);
    285         } else if (mValidity > 1000) {
    286             setErrorMessage("Key certificate validity must be between 1 and 1000 years.");
    287             setPageComplete(false);
    288             return;
    289         }
    290 
    291         if (mDName == null || mDName.length() == 0) {
    292             setErrorMessage("At least one Certificate issuer field is required to be non-empty.");
    293             setPageComplete(false);
    294             return;
    295         }
    296 
    297         setPageComplete(true);
    298     }
    299 
    300     /**
    301      * Handles changes in the DName fields.
    302      */
    303     private void onDNameChange() {
    304         StringBuilder sb = new StringBuilder();
    305 
    306         buildDName("CN", mCnField, sb);
    307         buildDName("OU", mOuField, sb);
    308         buildDName("O", mOField, sb);
    309         buildDName("L", mLField, sb);
    310         buildDName("ST", mStField, sb);
    311         buildDName("C", mCField, sb);
    312 
    313         mDName = sb.toString();
    314         mWizard.setDName(mDName);
    315 
    316         onChange();
    317     }
    318 
    319     /**
    320      * Builds the distinguished name string with the provided {@link StringBuilder}.
    321      * @param prefix the prefix of the entry.
    322      * @param textField The {@link Text} field containing the entry value.
    323      * @param sb the string builder containing the dname.
    324      */
    325     private void buildDName(String prefix, Text textField, StringBuilder sb) {
    326         if (textField != null) {
    327             String value = textField.getText().trim();
    328             if (value.length() > 0) {
    329                 if (sb.length() > 0) {
    330                     sb.append(",");
    331                 }
    332 
    333                 sb.append(prefix);
    334                 sb.append('=');
    335                 sb.append(value);
    336             }
    337         }
    338     }
    339 }
    340