Browse Source

Try to keep track of channel keys (Close Issue #108)

 - Parses outgoing JOINs to try and guess keys before we get the MODE reply.
   - Parsing algorithm based on Quakenet/Hybrid handling of keys.
     - Keys are swallowed from the key-list for EVERY channel that is
       to join, even if it is not needed, so you would need to use
       "JOIN #Foo,#Bar,#Baz Foo,,Baz" to join keyed channels #Foo and #Baz.
 - Key changes by mode +k and -k will be tracked.
 - Ignores attempts to set the key as "*" if we know a "better" key.
   - Side effect: If the key is actually set to "*" we can only learn it if that
     is what we join with, or it gets changed to that from no-key.
pull/111/head
Shane Mc Cormack 8 years ago
parent
commit
a2af0c5851

+ 5
- 0
common/src/com/dmdirc/parser/common/BaseChannelInfo.java View File

@@ -68,6 +68,11 @@ public abstract class BaseChannelInfo implements ChannelInfo {
68 68
         return parser;
69 69
     }
70 70
 
71
+    @Override
72
+    public String getPassword() {
73
+        return "";
74
+    }
75
+
71 76
     @Override
72 77
     public void sendMessage(final String message) {
73 78
         parser.sendMessage(name, message);

+ 7
- 0
common/src/com/dmdirc/parser/interfaces/ChannelInfo.java View File

@@ -42,6 +42,13 @@ public interface ChannelInfo {
42 42
      */
43 43
     String getName();
44 44
 
45
+    /**
46
+     * Returns the password for this channel.
47
+     *
48
+     * @return The password for this channel
49
+     */
50
+    String getPassword();
51
+
45 52
     /**
46 53
      * Changes the topic of this channel.
47 54
      *

+ 23
- 0
irc/src/com/dmdirc/parser/irc/IRCChannelInfo.java View File

@@ -72,6 +72,8 @@ public class IRCChannelInfo implements ChannelInfo {
72 72
     private final PrefixModeManager prefixModeManager;
73 73
     /** Channel Name. */
74 74
     private final String name;
75
+    /** Channel Key. */
76
+    private String password = "";
75 77
     /** Hashtable containing references to ChannelClients. */
76 78
     private final Map<String, IRCChannelClientInfo> clients = Collections.synchronizedMap(new HashMap<>());
77 79
     /** Hashtable storing values for modes set in the channel that use parameters. */
@@ -440,6 +442,20 @@ public class IRCChannelInfo implements ChannelInfo {
440 442
         return topicUser;
441 443
     }
442 444
 
445
+    @Override
446
+    public String getPassword() {
447
+        return password;
448
+    }
449
+
450
+    /**
451
+     * Set the internal value of the channel password,
452
+     *
453
+     * @param newValue New Value to set
454
+     */
455
+    public void setInternalPassword(final String newValue) {
456
+        password = newValue;
457
+    }
458
+
443 459
     /**
444 460
      * Set the channel modes.
445 461
      *
@@ -487,6 +503,13 @@ public class IRCChannelInfo implements ChannelInfo {
487 503
             }
488 504
         } else {
489 505
             paramModes.put(cMode, sValue);
506
+            if (cMode == 'k') {
507
+                if (sValue.equalsIgnoreCase("*") && !getPassword().equalsIgnoreCase("*")) {
508
+                    // Don't overwrite a guessed password with a hidden one.
509
+                    return;
510
+                }
511
+                setInternalPassword(sValue);
512
+            }
490 513
         }
491 514
     }
492 515
 

+ 43
- 0
irc/src/com/dmdirc/parser/irc/IRCParser.java View File

@@ -234,6 +234,10 @@ public class IRCParser extends BaseSocketAwareParser implements SecureParser, En
234 234
     private final WhoisResponseHandler whoisHandler;
235 235
     /** Used to synchronize calls to resetState. */
236 236
     private final Object resetStateSync = new Object();
237
+    /** Pending Joins. */
238
+    private final Queue<String> pendingJoins = new LinkedList<>();
239
+    /** Pending Join Keys. */
240
+    private final Queue<String> pendingJoinKeys = new LinkedList<>();
237 241
 
238 242
     /**
239 243
      * Default constructor, ServerInfo and MyInfo need to be added separately (using IRC.me and IRC.server).
@@ -1055,11 +1059,50 @@ public class IRCParser extends BaseSocketAwareParser implements SecureParser, En
1055 1059
                     }
1056 1060
                 }
1057 1061
             }
1062
+        } else if ("join".equalsIgnoreCase(newLine[0]) && newLine.length > 1) {
1063
+            final Queue<String> keys = new LinkedList<>();
1064
+
1065
+            if (newLine.length > 2) {
1066
+                keys.addAll(Arrays.asList(newLine[2].split(",")));
1067
+            }
1068
+
1069
+            // PendingJoins and PendingJoinKeys should always be the same length (even if no key was given).
1070
+            //
1071
+            // We don't get any errors for channels we try to join that we are already in
1072
+            // But the IRCD will still swallow the key attempt.
1073
+            //
1074
+            // Make sure that we always have a guessed key for every channel (even if null) and that we
1075
+            // don't have guesses for channels we are already in.
1076
+            for (final String chan : newLine[1].split(",")) {
1077
+                final String key = keys.poll();
1078
+                if (getChannel(chan) == null) {
1079
+                    pendingJoins.add(chan);
1080
+                    pendingJoinKeys.add(key);
1081
+                }
1082
+            }
1058 1083
         }
1059 1084
 
1060 1085
         return true;
1061 1086
     }
1062 1087
 
1088
+    /**
1089
+     * Get the current pending Joins.
1090
+     *
1091
+     * @return Current pending Joins
1092
+     */
1093
+    public Queue<String> getPendingJoins() {
1094
+        return pendingJoins;
1095
+    }
1096
+
1097
+    /**
1098
+     * Get the current pending join keys.
1099
+     *
1100
+     * @return Current pending join keys.
1101
+     */
1102
+    public Queue<String> getPendingJoinKeys() {
1103
+        return pendingJoinKeys;
1104
+    }
1105
+
1063 1106
     @Override
1064 1107
     public String getNetworkName() {
1065 1108
         return networkName;

+ 17
- 3
irc/src/com/dmdirc/parser/irc/processors/ProcessJoin.java View File

@@ -67,7 +67,7 @@ public class ProcessJoin extends IRCProcessor {
67 67
     public ProcessJoin(final IRCParser parser, final PrefixModeManager prefixModeManager,
68 68
             @Named("user") final ModeManager userModeManager,
69 69
             @Named("channel") final ModeManager chanModeManager) {
70
-        super(parser, "JOIN", "329");
70
+        super(parser, "JOIN", "329", "471", "473", "474", "475", "476", "477", "479");
71 71
         this.prefixModeManager = prefixModeManager;
72 72
         this.userModeManager = userModeManager;
73 73
         this.chanModeManager = chanModeManager;
@@ -95,14 +95,13 @@ public class ProcessJoin extends IRCProcessor {
95 95
                     // Oh well, not a normal ircd I guess
96 96
                 }
97 97
             }
98
-        } else {
98
+        } else if ("JOIN".equals(sParam)) {
99 99
             // :nick!ident@host JOIN (:)#Channel
100 100
             if (token.length < 3) {
101 101
                 return;
102 102
             }
103 103
             final boolean extendedJoin = parser.getCapabilityState("extended-join") == CapabilityState.ENABLED;
104 104
 
105
-
106 105
             IRCClientInfo iClient = getClientInfo(token[0]);
107 106
             final String realName;
108 107
             final String accountName;
@@ -172,7 +171,22 @@ public class ProcessJoin extends IRCProcessor {
172 171
             parser.addChannel(iChannel);
173 172
             sendString("MODE " + iChannel.getName(), QueuePriority.LOW);
174 173
 
174
+            final String pendingJoin = parser.getPendingJoins().poll();
175
+            final String pendingJoinKey = parser.getPendingJoinKeys().poll();
176
+            if (pendingJoin.equalsIgnoreCase(channelName)) {
177
+                callDebugInfo(IRCParser.DEBUG_INFO, "processJoin: Guessing channel Key: " + pendingJoin + " -> " + pendingJoinKey);
178
+                iChannel.setInternalPassword(pendingJoinKey == null ? "" : pendingJoinKey);
179
+            } else {
180
+                // Out of sync, clear.
181
+                parser.getPendingJoins().clear();
182
+                parser.getPendingJoinKeys().clear();
183
+            }
184
+
175 185
             callChannelSelfJoin(iChannel);
186
+        } else {
187
+            // Some kind of failed to join, pop the pending join queues.
188
+            parser.getPendingJoins().poll();
189
+            parser.getPendingJoinKeys().poll();
176 190
         }
177 191
     }
178 192
 

Loading…
Cancel
Save