/*******************************************************************************
* Copyright (c) 2013, 2014 Lectorius, Inc.
* Authors:
* Vijay Pandurangan (vijayp@mitro.co)
* Evan Jones (ej@mitro.co)
* Adam Hilss (ahilss@mitro.co)
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact the authors at inbound@mitro.co.
*******************************************************************************/
package co.mitro.core.servlets;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.annotation.WebServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import co.mitro.core.crypto.KeyInterfaces.KeyFactory;
import co.mitro.core.exceptions.InvalidRequestException;
import co.mitro.core.exceptions.MitroServletException;
import co.mitro.core.exceptions.UserExistsException;
import co.mitro.core.server.ManagerFactory;
import co.mitro.core.server.data.DBAcl;
import co.mitro.core.server.data.DBAudit;
import co.mitro.core.server.data.DBEmailQueue;
import co.mitro.core.server.data.DBIdentity;
import co.mitro.core.server.data.RPC;
import co.mitro.core.server.data.RPC.AddGroupRequest;
import co.mitro.core.server.data.RPC.AddGroupResponse;
import co.mitro.core.server.data.RPC.MitroRPC;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
@WebServlet("/api/AddIdentity")
public class AddIdentity extends MitroServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(AddIdentity.class);
/**
* If false, new users are not verified. Set to true to disable verification.
* TODO: Fix regression tests and remove this flag.
* TODO: This is not thread-safe.
*/
public static boolean defaultVerifiedState = false;
public AddIdentity(ManagerFactory managerFactory, KeyFactory keyFactory) {
super(managerFactory, keyFactory);
}
protected boolean isReadOnly() {
return false;
}
@Override
protected MitroRPC processCommand(MitroRequestContext context)
throws IOException, SQLException, MitroServletException {
// The requestor's signature is verified by MitroServlet.doPost()
RPC.AddIdentityRequest in = gson.fromJson(context.jsonRequest, RPC.AddIdentityRequest.class);
DBIdentity iden = new DBIdentity();
if (null != DBIdentity.getIdentityForUserName(context.manager, in.userId)) {
throw new UserExistsException(in.userId);
}
if (!Util.isEmailAddress(in.userId)) {
throw new InvalidRequestException(
String.format("Address '%s' is not a valid email address", in.userId));
}
iden.setVerified(defaultVerifiedState);
iden.setName(in.userId);
iden.setEncryptedPrivateKeyString(in.encryptedPrivateKey);
iden.setPublicKeyString(in.publicKey);
iden.setAnalyticsId(in.analyticsId);
DBIdentity.createUserInDb(context.manager, iden);
// send the validation email
DBEmailQueue email =
DBEmailQueue.makeAddressVerification(iden.getName(), iden.getVerificationUid(), context.requestServerUrl);
context.manager.emailDao.create(email);
if (defaultVerifiedState) {
logger.warn("Email verification disabled for user: {}", iden.getName());
}
RPC.AddIdentityResponse out = new RPC.AddIdentityResponse();
out.verified = iden.isVerified();
out.unsignedLoginToken = GetMyPrivateKey.makeLoginTokenString(iden, null, in.deviceId);
context.manager.addAuditLog(DBAudit.ACTION.CREATE_IDENTITY, iden, null, null, null, null);
if (!Strings.isNullOrEmpty(in.groupKeyEncryptedForMe) && !Strings.isNullOrEmpty(in.groupPublicKey)) {
AddGroupRequest rqst = new AddGroupRequest();
rqst.autoDelete = false;
rqst.publicKey = in.groupPublicKey;
rqst.signatureString = "TODO"; // this mimics what the js code does.
rqst.name = ""; // this cannot be null.
rqst.acls = Lists.newArrayList();
AddGroupRequest.ACL acl = new AddGroupRequest.ACL();
acl.groupKeyEncryptedForMe = in.groupKeyEncryptedForMe;
acl.level = DBAcl.AccessLevelType.ADMIN;
acl.memberIdentity = iden.getName();
acl.myPublicKey = iden.getPublicKeyString();
rqst.acls.add(acl);
AddGroupResponse rsp = (AddGroupResponse) new AddGroup().processCommand(new MitroRequestContext(iden, gson.toJson(rqst), context.manager, context.platform));
out.privateGroupId = rsp.groupId;
}
// authorize this device
assert(!Strings.isNullOrEmpty(in.deviceId));
GetMyDeviceKey.maybeGetOrCreateDeviceKey(context.manager, iden, in.deviceId, false, context.platform);
return out;
}
}