001package com.pusher.rest.util; 002 003import java.security.InvalidKeyException; 004import java.security.NoSuchAlgorithmException; 005import java.util.Arrays; 006import java.util.HashSet; 007import java.util.List; 008import java.util.Map; 009import java.util.Set; 010import java.util.regex.Pattern; 011 012import javax.crypto.Mac; 013import javax.crypto.spec.SecretKeySpec; 014 015public final class Prerequisites { 016 017 private static final Pattern VALID_CHANNEL = Pattern.compile("\\A[-a-zA-Z0-9_=@,.;]+\\z"); 018 private static final Pattern VALID_SOCKET_ID = Pattern.compile("\\A\\d+\\.\\d+\\z"); 019 020 private static final Set<String> RESERVED_QUERY_KEYS = new HashSet<String>( 021 Arrays.asList(new String[] { "auth_key", "auth_timestamp", "auth_version", "auth_signature", "body_md5" })); 022 023 public static void nonNull(final String name, final Object ref) { 024 if (ref == null) throw new IllegalArgumentException("Parameter [" + name + "] must not be null"); 025 } 026 027 public static void nonEmpty(final String name, final String ref) { 028 nonNull(name, ref); 029 if (ref.length() == 0) throw new IllegalArgumentException("Parameter [" + name + "] must not be empty"); 030 } 031 032 public static void maxLength(final String name, final int max, final List<?> ref) { 033 if (ref.size() > max) throw new IllegalArgumentException("Parameter [" + name + "] must have size < " + max); 034 } 035 036 public static void noNullMembers(final String name, final List<?> ref) { 037 for (Object e : ref) { 038 if (e == null) throw new IllegalArgumentException("Parameter [" + name + "] must not contain null elements"); 039 } 040 } 041 042 public static void noReservedKeys(final Map<String, String> params) { 043 for (String k : params.keySet()) { 044 if (RESERVED_QUERY_KEYS.contains(k.toLowerCase())) { 045 throw new IllegalArgumentException("Query parameter key [" + k + "] is reserved and should not be submitted. It will be generated by the signature generation."); 046 } 047 } 048 } 049 050 public static void isValidSha256Key(final String name, final String key) { 051 try { 052 Mac mac = Mac.getInstance("HmacSHA256"); 053 mac.init(new SecretKeySpec(key.getBytes(), "SHA256")); 054 // If that goes OK, then we're good to go 055 } 056 catch (final NoSuchAlgorithmException e) { 057 // Out of luck. 058 throw new RuntimeException("The Pusher HTTP client requires HmacSHA256 support", e); 059 } 060 catch (final InvalidKeyException e) { 061 // Failed the test 062 throw new IllegalArgumentException("Parameter [" + name + "] must be a valid SHA256 key", e); 063 } 064 } 065 066 public static void areValidChannels(final List<String> channels) { 067 for (String channel : channels) { 068 isValidChannel(channel); 069 } 070 } 071 072 public static void isValidChannel(final String channel) { 073 matchesRegex("channel", VALID_CHANNEL, channel); 074 } 075 076 public static void isValidSocketId(final String socketId) { 077 if (socketId != null) { 078 matchesRegex("socket_id", VALID_SOCKET_ID, socketId); 079 } 080 } 081 082 private static void matchesRegex(final String name, final Pattern regex, final String toMatch) { 083 nonNull(name, toMatch); 084 if (!regex.matcher(toMatch).matches()) { 085 throw new IllegalArgumentException(name + " [" + toMatch + "] is not valid"); 086 } 087 } 088}