// Copyright 2008 Google Inc. All Rights Reserved. package org.waveprotocol.wave.model.util; import org.waveprotocol.wave.model.wave.ParticipantId; /** * Utility methods for participant IDs. * * */ public final class ParticipantIdUtil { /** Unknown participant ID */ public static final ParticipantId UNKNOWN = new ParticipantId("unknown"); private ParticipantIdUtil() {} /** * Normalises an address. * * @param address address to normalise; may be null * @return normal form of {@code address} if non-null; null otherwise. */ // TODO(ohler): Make this not nullable. public static String normalize(String address) { if (address == null) { return null; } return address.toLowerCase(); } /** * @param x a String * @return true if x is a wave address and normalized */ // NOTE(ohler), 2009-10-27: // Unfortunately, not all addresses in our database are normalized: // Some deltas contain authors of "<nobody>" and similar (not wave // addresses), or may contain upper-case characters (not // normalized). For future deltas, however, the wave server // enforces that they have normalized addresses as their authors and // as participant IDs in add/remove participant ops. // // If the federation code that serves outgoing deltas encounters a // (historic) delta that does not satisfy this constraint, it will // try to normalize the addresses in case the problem is just // upper-case characters, but if there's a junk address like // "<nobody>" that normalization doesn't fix, the entire wavelet // will become non-federable. public static boolean isNormalizedAddress(String x) { Preconditions.checkNotNull(x, "Null address"); // TODO(ohler): Define what wave addresses really are, and add proper checks here. if (!x.equals(normalize(x))) { return false; } int at = x.indexOf('@'); return at > 0 && isValidDomain(at + 1, x); } /** * Checks if the given string has a valid host name specified, starting at the * given start index. This method implements a check for a valid domain as * specified by RFC 1035, Section 2.3.1. It essentially checks if the domain * matches the following regular expression: * <tt>[a-z0-9]([a-z0-9\-]*[a-z0-9])(\.[a-z0-9]([a-z0-9\-]*[a-z0-9]))*</tt>. * Please note that the specification does not restrict TLDs, and therefore * my.arbitrary.domain passes the check. We also allow labels to start with * a digit to allow for domains such as 76.com. Furthermore, we allow only * strings specified by the subdomain non-terminal,to avoid allowing empty * string, which can be derived from the domain non-terminal. */ public static boolean isValidDomain(int start, String x) { // TODO(user): Make sure we accept only valid TLDs. int index = start; int length = x.length() - start; if (length > 253 || length < 1) { return false; } while (index < x.length()) { char c = x.charAt(index); // A label must being with a letter or a digit. if (('a' > c || c > 'z') && ('0' > c || c > '9')) { return false; } char d = c; while (++index < x.length()) { c = x.charAt(index); // Subsequent characters may be letters, digits or the dash. if (('a' > c || c > 'z') && ('0' > c || c > '9') && (c != '-')) { break; } d = c; } if (index >= x.length()) { return d != '-'; } // Labels must be separated by dots, and may not end with the dash. if ('.' != c || d == '-') { return false; } ++index; } // The domain ended in a dot, legal but we do not approve. return false; } }