001/*
002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003 * Copyright (C) 2011 NightLabs Consulting GmbH
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package co.codewizards.cloudstore.client;
019
020import java.util.UUID;
021
022import org.kohsuke.args4j.Argument;
023
024import co.codewizards.cloudstore.core.repo.local.LocalRepoManager;
025import co.codewizards.cloudstore.core.repo.local.LocalRepoManagerFactory;
026import co.codewizards.cloudstore.core.repo.local.LocalRepoTransaction;
027import co.codewizards.cloudstore.core.util.HashUtil;
028import co.codewizards.cloudstore.local.persistence.RemoteRepositoryRequest;
029import co.codewizards.cloudstore.local.persistence.RemoteRepositoryRequestDAO;
030
031/**
032 * {@link SubCommand} implementation for requesting a connection at a remote repository.
033 *
034 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
035 */
036public class AcceptRepoConnectionSubCommand extends SubCommandWithExistingLocalRepo
037{
038        @Argument(metaVar="<remote>", index=1, required=false, usage="The unique ID of a remote repository currently requesting to be connected. If none is specified, the oldest request is accepted.")
039        private String remote;
040
041        private UUID remoteRepositoryId;
042
043        @Override
044        public String getSubCommandDescription() {
045                return "Accept a connection request from a remote repository.";
046        }
047
048        @Override
049        public void prepare() throws Exception {
050                super.prepare();
051                remoteRepositoryId = remote == null ? null : UUID.fromString(remote);
052        }
053
054        @Override
055        public void run() throws Exception {
056                UUID localRepositoryId;
057                byte[] localPublicKey;
058                byte[] remotePublicKey;
059                String localPathPrefix;
060                LocalRepoManager localRepoManager = LocalRepoManagerFactory.Helper.getInstance().createLocalRepoManagerForExistingRepository(localRoot);
061                try {
062                        localRepositoryId = localRepoManager.getRepositoryId();
063                        localPublicKey = localRepoManager.getPublicKey();
064                        LocalRepoTransaction transaction = localRepoManager.beginWriteTransaction();
065                        try {
066                                RemoteRepositoryRequestDAO remoteRepositoryRequestDAO = transaction.getDAO(RemoteRepositoryRequestDAO.class);
067                                RemoteRepositoryRequest request;
068                                if (remoteRepositoryId == null) {
069                                        RemoteRepositoryRequest oldestRequest = null;
070                                        for (RemoteRepositoryRequest remoteRepositoryRequest : remoteRepositoryRequestDAO.getObjects()) {
071                                                if (oldestRequest == null || oldestRequest.getChanged().after(remoteRepositoryRequest.getChanged()))
072                                                        oldestRequest = remoteRepositoryRequest;
073                                        }
074                                        if (oldestRequest == null)
075                                                throw new IllegalStateException("There is no connection request pending for this local repository: " + localRoot.getPath());
076
077                                        request = oldestRequest;
078                                }
079                                else {
080                                        request = remoteRepositoryRequestDAO.getRemoteRepositoryRequestOrFail(remoteRepositoryId);
081                                }
082                                remoteRepositoryId = request.getRepositoryId();
083                                remotePublicKey = request.getPublicKey();
084                                localPathPrefix = request.getLocalPathPrefix();
085                                transaction.commit();
086                        } finally {
087                                transaction.rollbackIfActive();
088                        }
089                        localRepoManager.putRemoteRepository(remoteRepositoryId, null, remotePublicKey, localPathPrefix); // deletes the request.
090                } finally {
091                        localRepoManager.close();
092                }
093
094                System.out.println("Successfully accepted the connection request for the following local and remote repositories:");
095                System.out.println();
096                System.out.println("  localRepository.repositoryId = " + localRepositoryId);
097                System.out.println("  localRepository.localRoot = " + localRoot);
098                System.out.println("  localRepository.publicKeySha1 = " + HashUtil.sha1ForHuman(localPublicKey));
099                System.out.println();
100                System.out.println("  remoteRepository.repositoryId = " + remoteRepositoryId);
101                System.out.println("  remoteRepository.publicKeySha1 = " + HashUtil.sha1ForHuman(remotePublicKey));
102                System.out.println();
103                System.out.println("Please verify the 'publicKeySha1' fingerprints! If they do not match the fingerprints shown on the client, someone is attacking you and you must cancel this request immediately! To cancel the request, use this command:");
104                System.out.println();
105                System.out.println(String.format("  cloudstore dropRepoConnection %s %s", localRepositoryId, remoteRepositoryId));
106        }
107}