001    package org.apache.maven.scm.provider.cvslib.command.login;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     * http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.maven.scm.ScmException;
023    import org.apache.maven.scm.log.ScmLogger;
024    
025    import java.io.BufferedReader;
026    import java.io.File;
027    import java.io.FileReader;
028    import java.io.FileWriter;
029    import java.io.IOException;
030    import java.io.PrintWriter;
031    
032    /**
033     * Adds an new entry to a CVS password file.
034     *
035     * @version $Id: CvsPass.java 1306867 2012-03-29 13:45:10Z olamy $
036     * @todo Update this class for support password storage in cvsnt. CVSNT use the windows registry, so, we need a jni
037     * tool for access to the windows registry
038     */
039    public class CvsPass
040    {
041        /**
042         * CVS Root
043         */
044        private String cvsRoot = null;
045    
046        /**
047         * Password file to add password to
048         */
049        private File passFile = null;
050    
051        /**
052         * Password to add to file
053         */
054        private String password = null;
055    
056        private ScmLogger logger;
057    
058        /**
059         * Array contain char conversion data
060         */
061        private final char[] shifts = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
062            24, 25, 26, 27, 28, 29, 30, 31, 114, 120, 53, 79, 96, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, 111, 52,
063            75, 119, 49, 34, 82, 81, 95, 65, 112, 86, 118, 110, 122, 105, 41, 57, 83, 43, 46, 102, 40, 89, 38, 103, 45, 50,
064            42, 123, 91, 35, 125, 55, 54, 66, 124, 126, 59, 47, 92, 71, 115, 78, 88, 107, 106, 56, 36, 121, 117, 104, 101,
065            100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, 58, 113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85, 223,
066            225, 216, 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190, 199, 170, 181, 204, 138, 232,
067            218, 183, 255, 234, 220, 247, 213, 203, 226, 193, 174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238,
068            161, 179, 160, 212, 207, 221, 254, 173, 202, 146, 224, 151, 140, 196, 205, 130, 135, 133, 143, 246, 192, 159,
069            244, 239, 185, 168, 215, 144, 139, 165, 180, 157, 147, 186, 214, 176, 227, 231, 219, 169, 175, 156, 206, 198,
070            129, 164, 150, 210, 154, 177, 134, 127, 182, 128, 158, 208, 162, 132, 167, 209, 149, 241, 153, 251, 237, 236,
071            171, 195, 243, 233, 253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152};
072    
073        /**
074         * Create a CVS task using the default cvspass file location.
075         */
076        public CvsPass( ScmLogger logger )
077        {
078            passFile = new File( System.getProperty( "cygwin.user.home", System.getProperty( "user.home" ) ) + File
079                .separatorChar + ".cvspass" );
080            this.logger = logger;
081        }
082    
083        /**
084         * Does the work.
085         *
086         * @throws ScmException if something is missing
087         * @throws IOException  if something goes wrong
088         */
089        public final void execute()
090            throws ScmException, IOException
091        {
092            if ( cvsRoot == null )
093            {
094                throw new ScmException( "cvsroot is required" );
095            }
096    
097            if ( logger.isDebugEnabled() )
098            {
099                logger.debug( "cvsRoot: " + cvsRoot );
100                logger.debug( "passFile: " + passFile );
101            }
102    
103            BufferedReader reader = null;
104    
105            PrintWriter writer = null;
106            try
107            {
108                StringBuilder buf = new StringBuilder();
109    
110                if ( passFile.exists() )
111                {
112                    reader = new BufferedReader( new FileReader( passFile ) );
113    
114                    String line = null;
115    
116                    while ( ( line = reader.readLine() ) != null )
117                    {
118                        if ( !line.startsWith( cvsRoot ) && !line.startsWith( "/1 " + cvsRoot ) )
119                        {
120                            buf.append( line ).append( "\n" );
121                        }
122                        else
123                        {
124                            if ( logger.isDebugEnabled() )
125                            {
126                                logger.debug( "cvsroot " + cvsRoot + " already exist in " + passFile.getAbsolutePath()
127                                    + ". SKIPPED." );
128                            }
129    
130                            return;
131                        }
132                    }
133                }
134                else
135                {
136                    passFile.getParentFile().mkdirs();
137                }
138    
139                if ( password == null )
140                {
141                    throw new ScmException( "password is required. You must run a 'cvs -d " + cvsRoot
142                        + " login' first or provide it in the connection url." );
143                }
144    
145                //logger.debug( "password: " + password );
146    
147                String pwdfile = buf.toString() + "/1 " + cvsRoot + " A" + mangle( password );
148    
149                if ( logger.isDebugEnabled() )
150                {
151                    logger.debug( "Writing -> " + pwdfile + " in " + passFile.getAbsolutePath() );
152                }
153    
154                writer = new PrintWriter( new FileWriter( passFile ) );
155    
156                writer.println( pwdfile );
157            }
158            finally
159            {
160                if ( reader != null )
161                {
162                    try
163                    {
164                        reader.close();
165                    }
166                    catch ( IOException e )
167                    {
168                        // ignore
169                    }
170                }
171                if ( writer != null )
172                {
173                    writer.close();
174                }
175            }
176        }
177    
178        private String mangle( String password )
179        {
180            StringBuilder buf = new StringBuilder();
181            for ( int i = 0; i < password.length(); i++ )
182            {
183                buf.append( shifts[password.charAt( i )] );
184            }
185            return buf.toString();
186        }
187    
188        /**
189         * The CVS repository to add an entry for.
190         *
191         * @param cvsRoot the CVS repository
192         */
193        public void setCvsroot( String cvsRoot )
194        {
195            this.cvsRoot = cvsRoot;
196        }
197    
198        /**
199         * Password file to add the entry to.
200         *
201         * @param passFile the password file.
202         */
203        public void setPassfile( File passFile )
204        {
205            this.passFile = passFile;
206        }
207    
208        /**
209         * Password to be added to the password file.
210         *
211         * @param password the password.
212         */
213        public void setPassword( String password )
214        {
215            this.password = password;
216        }
217    
218    }