//device本身不会直接收到connect消息,一个socket都是处理完connect消息,才和Device建立关联。 internal void OnConnectMessageReceived(IChannel channel, ConnectMessage cm) { var sessionCode = cm.SessionCode; //对方发了一个SessionCode,表示以前可能连接过? if (!string.IsNullOrEmpty(sessionCode)) { if (Crypto != null) { sessionCode = Crypto.Decrypt(sessionCode); } //确实连接过。而且还没过期。自动同意这个设备。 if (sessionCode == SessionCode) { ConnectingOutTimer?.Stop(); //原来的channel应该是坏掉了,不然对方为什么要发Connect消息呢?所以换成对方创建的channel. IsRequester = false; SwitchChannel(channel); //先换channel才能成功发送Accept消息。 Accept(); return; } } //如果没有SessionCode或者SessionCode不等于当前SessionCode. //启动全新连接流程。 if (!string.IsNullOrEmpty(cm.ChallengeString)) { //对方要求加密 cm.ExtractToDevice(this); //其实验证还是可以在B这一端完成。因为A可以用它自己的密码加密它的密码。如果B输入的密码和解出来的密码一致,就认为认证成功, //并发送Accept消息给A, 最终还是要由A确认是否进入可通讯状态。所以改成那个方案意义不太大。 //还是要有这么个字段,因为ChallengeRequest这个字段,在ConnectingIn的事件处理中,在Accept的时候要用。 ChallengeRequest = cm.ChallengeString; IsRequester = false; SwitchChannel(channel); bool shouldAskUserInput = true; //对方是否知道我的ConnectCode? if (!string.IsNullOrEmpty(cm.ConnectCode)) { //对方发来的ConnectCode是加密的 //我看一下是不是用我的密码加密的?我能判断是因为EncedConnectCode的原值就是ConnectCode(原始内容其实并不一定是ConnectCode,现在用了,只是为了方便)。 var ld = AppModel.Instance.LocalDevice; string connectCode = null; using (var sp = new SecurePassword(ld.ConnectCode)) using (var crypto = Env.Instance.SecurityManager.CreateCrypto(sp)) { connectCode = crypto.Decrypt(cm.ConnectCode); } if (connectCode != null && connectCode == ld.ConnectCode) { if (Env.Instance.Config.PairedDevice != null && Env.Instance.Config.PairedDevice.ID != ID) { Reject(RejectMessage.ALLOW_ONLY_ONE_PAIR_DEVICE); } //对方知道ChannelCode,并正确的用这个ChannelCode给它自己的ID加了密。 ChannelCode = new SecurePassword(connectCode); Accept(); Env.Instance.Config.PairedDevice = this; Env.Instance.Config.Save(); shouldAskUserInput = false; } else { Reject(RejectMessage.CONNECT_CODE_INCORRECT); return; } } if (shouldAskUserInput) { State = DeviceState.ConnectingIn; } return; } else { //对方不要求加密。 this.ChallengeRequest = null; if (State == DeviceState.ConnectingOut) { //如果是我去连接别人了,别人同时,或者稍后,给我发了ConnectMessage。 cm.ExtractToDevice(this); TryAutoAccept(channel); } else if (State == DeviceState.ConnectingIn) { //如果刚刚已经连接进来,并等待批准,为什么还要再连接? } else { //可能是通过广播搜到的,也可能是别人拍了我的二维码主动连过来的,现在开始发起实际连接了,从前没有成功连接过。 cm.ExtractToDevice(this);//如果没有发现别人,别人直接连过来了,这个动作做了两次。没办法。本来在这里做最合适。但那里要汇报deviceDiscovered。 IsRequester = false; SwitchChannel(channel); var app = AppModel.Instance; var config = Env.Instance.Config; //如果这个设备在信任设备列表中。 if (!string.IsNullOrEmpty(cm.ConnectCode) && cm.ConnectCode == app.LocalDevice.ConnectCode) { //如果这个设备所代表的对方发送了一个ConnectCode,而且这个ConnectCode与本机的ConnectCode一致,说明对方知道我的口令,自动同意连接。而且添加为信任设备 //TODO bug 这样还不够,应该从AppModel里面去取Device,然后再add或者replace,让所有的地方都只保留一个Device的引用。 //不过Device这个类应该是保证了它一定是AppModel里面的。因为在Connect之前已经检查了。 config.TrustDevices.AddOrReplace(this); config.Save(); } //如果上面成功添加了可信设备,这里就会自动接受了。 if (config.TrustDevices.FirstOrDefault(d => d.ID == this.ID) != null) { Accept(); } else { //这会触发ConnectingIn事件,用户可以决定是否同意这个连接。 State = DeviceState.ConnectingIn; } } } }
//device本身不会直接收到connect消息,一个socket都是处理完connect消息,才和Device建立关联。 internal void OnConnectMessageReceived(IChannel channel, ConnectMessage cm) { var sessionCode = cm.SessionCode; //对方发了一个SessionCode,表示以前可能连接过? if (!string.IsNullOrEmpty(sessionCode)) { //确实连接过。而且还没过期。自动同意这个设备。 if (sessionCode == SessionCode) { ConnectingOutTimer?.Stop(); //原来的channel应该是坏掉了,不然对方为什么要发Connect消息呢?所以换成对方创建的channel. IsRequester = false; SwitchChannel(channel); //先换channel才能成功发送Accept消息。 Accept(); return; } } else { //对方不要求加密。 this.ChallengeRequest = null; if (State == DeviceState.ConnectingOut) { //如果是我去连接别人了,别人同时,或者稍后,给我发了ConnectMessage。 cm.ExtractToDevice(this); TryAutoAccept(channel); } else if (State == DeviceState.ConnectingIn) { //如果刚刚已经连接进来,并等待批准,为什么还要再连接? } else { //可能是通过广播搜到的,也可能是别人拍了我的二维码主动连过来的,现在开始发起实际连接了,从前没有成功连接过。 cm.ExtractToDevice(this);//如果没有发现别人,别人直接连过来了,这个动作做了两次。没办法。本来在这里做最合适。但那里要汇报deviceDiscovered。 IsRequester = false; SwitchChannel(channel); var app = AppModel.Instance; var config = Env.Instance.Config; //如果这个设备在信任设备列表中。 if (!string.IsNullOrEmpty(cm.ConnectCode) && cm.ConnectCode == app.LocalDevice.ConnectCode) { //如果这个设备所代表的对方发送了一个ConnectCode,而且这个ConnectCode与本机的ConnectCode一致,说明对方知道我的口令,自动同意连接。而且添加为信任设备 //TODO bug 这样还不够,应该从AppModel里面去取Device,然后再add或者replace,让所有的地方都只保留一个Device的引用。 //不过Device这个类应该是保证了它一定是AppModel里面的。因为在Connect之前已经检查了。 config.TrustDevices.AddOrReplace(this); config.Save(); } //如果上面成功添加了可信设备,这里就会自动接受了。 if (config.TrustDevices.FirstOrDefault(d => d.ID == this.ID) != null) { Accept(); } else { //这会触发ConnectingIn事件,用户可以决定是否同意这个连接。 State = DeviceState.ConnectingIn; } } } }