");
+ defaults.put("toggle.success", "&e[xAuth] Node %1.");
+
+ defaults.put("logout.err.session", "&cThis player does not have an active session.");
+ defaults.put("logout.success.ended", "&cYour session has been terminated. You must log in again.");
+ defaults.put("logout.success.other", "&a%1's session has been terminated.");
+
+ defaults.put("password.invalid", "&cYour password must contain %1 or more characters.");
+
+ defaults.put("misc.illegal", "&7You must be logged in to do that!");
+ defaults.put("misc.reloaded", "&cServer reloaded! You must log in again.");
+ defaults.put("misc.enabled", "enabled");
+ defaults.put("misc.disabled", "disabled");
+ defaults.put("misc.filterkickmsg", "Your name contains one or more illegal characters.");
+ defaults.put("misc.blankkickmsg", "Blank names are not allowed.");
+ }
+
+ private void updateKeys()
+ {
+ String fromKey, toKey, holder;
+ for (String[] update : keyUpdates)
+ {
+ fromKey = update[0];
+ if (config.getProperty(fromKey) != null)
+ {
+ toKey = update[1];
+ holder = config.getString(fromKey);
+ config.removeProperty(fromKey);
+ if (!toKey.equals(""))
+ config.setProperty(toKey, holder);
+ }
+ }
+ }
+
+ private void removeKeys()
+ {
+ for (String key : keyRemovals)
+ {
+ if (config.getProperty(key) != null)
+ config.removeProperty(key);
+ }
+ }
+
+ private void load()
+ {
+ for (String key : keys)
+ {
+ if (config.getProperty(key) == null)
+ config.setProperty(key, defaults.get(key));
+ strings.put(key, config.getString(key).replace("&", "\u00a7"));
+ }
+
+ //clear defaults to free memory
+ defaults.clear();
+ }
+
+ public String getString(String key)
+ {
+ return strings.get(key);
+ }
+
+ public String getString(String key, Object replacement)
+ {
+ return strings.get(key).replace("%1", replacement.toString());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/cypherx/xauth/Whirlpool.java b/src/main/java/com/cypherx/xauth/Whirlpool.java
new file mode 100644
index 0000000..de10657
--- /dev/null
+++ b/src/main/java/com/cypherx/xauth/Whirlpool.java
@@ -0,0 +1,559 @@
+package com.cypherx.xauth;
+
+/**
+ * The Whirlpool hashing function.
+ *
+ *
+ * References
+ *
+ *
+ * The Whirlpool algorithm was developed by
+ * Paulo S. L. M. Barreto and
+ * Vincent Rijmen.
+ *
+ * See
+ * P.S.L.M. Barreto, V. Rijmen,
+ * ``The Whirlpool hashing function,''
+ * First NESSIE workshop, 2000 (tweaked version, 2003),
+ *
+ *
+ * @author Paulo S.L.M. Barreto
+ * @author Vincent Rijmen.
+ *
+ * @version 3.0 (2003.03.12)
+ *
+ * =============================================================================
+ *
+ * Differences from version 2.1:
+ *
+ * - Suboptimal diffusion matrix replaced by cir(1, 1, 4, 1, 8, 5, 2, 9).
+ *
+ * =============================================================================
+ *
+ * Differences from version 2.0:
+ *
+ * - Generation of ISO/IEC 10118-3 test vectors.
+ * - Bug fix: nonzero carry was ignored when tallying the data length
+ * (this bug apparently only manifested itself when feeding data
+ * in pieces rather than in a single chunk at once).
+ *
+ * Differences from version 1.0:
+ *
+ * - Original S-box replaced by the tweaked, hardware-efficient version.
+ *
+ * =============================================================================
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+import java.util.Arrays;
+
+class Whirlpool {
+
+ /**
+ * The message digest size (in bits)
+ */
+ public static final int DIGESTBITS = 512;
+
+ /**
+ * The message digest size (in bytes)
+ */
+ public static final int DIGESTBYTES = DIGESTBITS >>> 3;
+
+ /**
+ * The number of rounds of the internal dedicated block cipher.
+ */
+ protected static final int R = 10;
+
+ /**
+ * The substitution box.
+ */
+ private static final String sbox =
+ "\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152" +
+ "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57" +
+ "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85" +
+ "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8" +
+ "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333" +
+ "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0" +
+ "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE" +
+ "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d" +
+ "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF" +
+ "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A" +
+ "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c" +
+ "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04" +
+ "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB" +
+ "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9" +
+ "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1" +
+ "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886";
+
+ private static long[][] C = new long[8][256];
+ private static long[] rc = new long[R + 1];
+
+ static {
+ for (int x = 0; x < 256; x++) {
+ char c = sbox.charAt(x/2);
+ long v1 = ((x & 1) == 0) ? c >>> 8 : c & 0xff;
+ long v2 = v1 << 1;
+ if (v2 >= 0x100L) {
+ v2 ^= 0x11dL;
+ }
+ long v4 = v2 << 1;
+ if (v4 >= 0x100L) {
+ v4 ^= 0x11dL;
+ }
+ long v5 = v4 ^ v1;
+ long v8 = v4 << 1;
+ if (v8 >= 0x100L) {
+ v8 ^= 0x11dL;
+ }
+ long v9 = v8 ^ v1;
+ /*
+ * build the circulant table C[0][x] = S[x].[1, 1, 4, 1, 8, 5, 2, 9]:
+ */
+ C[0][x] =
+ (v1 << 56) | (v1 << 48) | (v4 << 40) | (v1 << 32) |
+ (v8 << 24) | (v5 << 16) | (v2 << 8) | (v9 );
+ /*
+ * build the remaining circulant tables C[t][x] = C[0][x] rotr t
+ */
+ for (int t = 1; t < 8; t++) {
+ C[t][x] = (C[t - 1][x] >>> 8) | ((C[t - 1][x] << 56));
+ }
+ }
+ /*
+ for (int t = 0; t < 8; t++) {
+ System.out.println("static const u64 C" + t + "[256] = {");
+ for (int i = 0; i < 64; i++) {
+ System.out.print(" ");
+ for (int j = 0; j < 4; j++) {
+ String v = Long.toHexString(C[t][4*i + j]);
+ while (v.length() < 16) {
+ v = "0" + v;
+ }
+ System.out.print(" LL(0x" + v + "),");
+ }
+ System.out.println();
+ }
+ System.out.println("};");
+ System.out.println();
+ }
+ System.out.println();
+ //*/
+
+ /*
+ * build the round constants:
+ */
+ rc[0] = 0L; /* not used (assigment kept only to properly initialize all variables) */
+ for (int r = 1; r <= R; r++) {
+ int i = 8*(r - 1);
+ rc[r] =
+ (C[0][i ] & 0xff00000000000000L) ^
+ (C[1][i + 1] & 0x00ff000000000000L) ^
+ (C[2][i + 2] & 0x0000ff0000000000L) ^
+ (C[3][i + 3] & 0x000000ff00000000L) ^
+ (C[4][i + 4] & 0x00000000ff000000L) ^
+ (C[5][i + 5] & 0x0000000000ff0000L) ^
+ (C[6][i + 6] & 0x000000000000ff00L) ^
+ (C[7][i + 7] & 0x00000000000000ffL);
+ }
+ /*
+ System.out.println("static const u64 rc[R + 1] = {");
+ for (int r = 0; r <= R; r++) {
+ String v = Long.toHexString(rc[r]);
+ while (v.length() < 16) {
+ v = "0" + v;
+ }
+ System.out.println(" LL(0x" + v + "),");
+ }
+ System.out.println("};");
+ System.out.println();
+ //*/
+ }
+
+ /**
+ * Global number of hashed bits (256-bit counter).
+ */
+ protected byte[] bitLength = new byte[32];
+
+ /**
+ * Buffer of data to hash.
+ */
+ protected byte[] buffer = new byte[64];
+
+ /**
+ * Current number of bits on the buffer.
+ */
+ protected int bufferBits = 0;
+
+ /**
+ * Current (possibly incomplete) byte slot on the buffer.
+ */
+ protected int bufferPos = 0;
+
+ /**
+ * The hashing state.
+ */
+ protected long[] hash = new long[8];
+ protected long[] K = new long[8]; // the round key
+ protected long[] L = new long[8];
+ protected long[] block = new long[8]; // mu(buffer)
+ protected long[] state = new long[8]; // the cipher state
+
+ public Whirlpool() {
+ }
+
+ /**
+ * The core Whirlpool transform.
+ */
+ protected void processBuffer() {
+ /*
+ * map the buffer to a block:
+ */
+ for (int i = 0, j = 0; i < 8; i++, j += 8) {
+ block[i] =
+ (((long)buffer[j ] ) << 56) ^
+ (((long)buffer[j + 1] & 0xffL) << 48) ^
+ (((long)buffer[j + 2] & 0xffL) << 40) ^
+ (((long)buffer[j + 3] & 0xffL) << 32) ^
+ (((long)buffer[j + 4] & 0xffL) << 24) ^
+ (((long)buffer[j + 5] & 0xffL) << 16) ^
+ (((long)buffer[j + 6] & 0xffL) << 8) ^
+ (((long)buffer[j + 7] & 0xffL) );
+ }
+ /*
+ * compute and apply K^0 to the cipher state:
+ */
+ for (int i = 0; i < 8; i++) {
+ state[i] = block[i] ^ (K[i] = hash[i]);
+ }
+ /*
+ * iterate over all rounds:
+ */
+ for (int r = 1; r <= R; r++) {
+ /*
+ * compute K^r from K^{r-1}:
+ */
+ for (int i = 0; i < 8; i++) {
+ L[i] = 0L;
+ for (int t = 0, s = 56; t < 8; t++, s -= 8) {
+ L[i] ^= C[t][(int)(K[(i - t) & 7] >>> s) & 0xff];
+ }
+ }
+ for (int i = 0; i < 8; i++) {
+ K[i] = L[i];
+ }
+ K[0] ^= rc[r];
+ /*
+ * apply the r-th round transformation:
+ */
+ for (int i = 0; i < 8; i++) {
+ L[i] = K[i];
+ for (int t = 0, s = 56; t < 8; t++, s -= 8) {
+ L[i] ^= C[t][(int)(state[(i - t) & 7] >>> s) & 0xff];
+ }
+ }
+ for (int i = 0; i < 8; i++) {
+ state[i] = L[i];
+ }
+ }
+ /*
+ * apply the Miyaguchi-Preneel compression function:
+ */
+ for (int i = 0; i < 8; i++) {
+ hash[i] ^= state[i] ^ block[i];
+ }
+ }
+
+ /**
+ * Initialize the hashing state.
+ */
+ public void NESSIEinit() {
+ Arrays.fill(bitLength, (byte)0);
+ bufferBits = bufferPos = 0;
+ buffer[0] = 0; // it's only necessary to cleanup buffer[bufferPos].
+ Arrays.fill(hash, 0L); // initial value
+ }
+
+ /**
+ * Delivers input data to the hashing algorithm.
+ *
+ * @param source plaintext data to hash.
+ * @param sourceBits how many bits of plaintext to process.
+ *
+ * This method maintains the invariant: bufferBits < 512
+ */
+ public void NESSIEadd(byte[] source, long sourceBits) {
+ /*
+ sourcePos
+ |
+ +-------+-------+-------
+ ||||||||||||||||||||| source
+ +-------+-------+-------
+ +-------+-------+-------+-------+-------+-------
+ |||||||||||||||||||||| buffer
+ +-------+-------+-------+-------+-------+-------
+ |
+ bufferPos
+ */
+ int sourcePos = 0; // index of leftmost source byte containing data (1 to 8 bits).
+ int sourceGap = (8 - ((int)sourceBits & 7)) & 7; // space on source[sourcePos].
+ int bufferRem = bufferBits & 7; // occupied bits on buffer[bufferPos].
+ int b;
+ // tally the length of the added data:
+ long value = sourceBits;
+ for (int i = 31, carry = 0; i >= 0; i--) {
+ carry += (bitLength[i] & 0xff) + ((int)value & 0xff);
+ bitLength[i] = (byte)carry;
+ carry >>>= 8;
+ value >>>= 8;
+ }
+ // process data in chunks of 8 bits:
+ while (sourceBits > 8) { // at least source[sourcePos] and source[sourcePos+1] contain data.
+ // take a byte from the source:
+ b = ((source[sourcePos] << sourceGap) & 0xff) |
+ ((source[sourcePos + 1] & 0xff) >>> (8 - sourceGap));
+ if (b < 0 || b >= 256) {
+ throw new RuntimeException("LOGIC ERROR");
+ }
+ // process this byte:
+ buffer[bufferPos++] |= b >>> bufferRem;
+ bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos;
+ if (bufferBits == 512) {
+ // process data block:
+ processBuffer();
+ // reset buffer:
+ bufferBits = bufferPos = 0;
+ }
+ buffer[bufferPos] = (byte)((b << (8 - bufferRem)) & 0xff);
+ bufferBits += bufferRem;
+ // proceed to remaining data:
+ sourceBits -= 8;
+ sourcePos++;
+ }
+ // now 0 <= sourceBits <= 8;
+ // furthermore, all data (if any is left) is in source[sourcePos].
+ if (sourceBits > 0) {
+ b = (source[sourcePos] << sourceGap) & 0xff; // bits are left-justified on b.
+ // process the remaining bits:
+ buffer[bufferPos] |= b >>> bufferRem;
+ } else {
+ b = 0;
+ }
+ if (bufferRem + sourceBits < 8) {
+ // all remaining data fits on buffer[bufferPos], and there still remains some space.
+ bufferBits += sourceBits;
+ } else {
+ // buffer[bufferPos] is full:
+ bufferPos++;
+ bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos;
+ sourceBits -= 8 - bufferRem;
+ // now 0 <= sourceBits < 8; furthermore, all data is in source[sourcePos].
+ if (bufferBits == 512) {
+ // process data block:
+ processBuffer();
+ // reset buffer:
+ bufferBits = bufferPos = 0;
+ }
+ buffer[bufferPos] = (byte)((b << (8 - bufferRem)) & 0xff);
+ bufferBits += (int)sourceBits;
+ }
+ }
+
+ /**
+ * Get the hash value from the hashing state.
+ *
+ * This method uses the invariant: bufferBits < 512
+ */
+ public void NESSIEfinalize(byte[] digest) {
+ // append a '1'-bit:
+ buffer[bufferPos] |= 0x80 >>> (bufferBits & 7);
+ bufferPos++; // all remaining bits on the current byte are set to zero.
+ // pad with zero bits to complete 512N + 256 bits:
+ if (bufferPos > 32) {
+ while (bufferPos < 64) {
+ buffer[bufferPos++] = 0;
+ }
+ // process data block:
+ processBuffer();
+ // reset buffer:
+ bufferPos = 0;
+ }
+ while (bufferPos < 32) {
+ buffer[bufferPos++] = 0;
+ }
+ // append bit length of hashed data:
+ System.arraycopy(bitLength, 0, buffer, 32, 32);
+ // process data block:
+ processBuffer();
+ // return the completed message digest:
+ for (int i = 0, j = 0; i < 8; i++, j += 8) {
+ long h = hash[i];
+ digest[j ] = (byte)(h >>> 56);
+ digest[j + 1] = (byte)(h >>> 48);
+ digest[j + 2] = (byte)(h >>> 40);
+ digest[j + 3] = (byte)(h >>> 32);
+ digest[j + 4] = (byte)(h >>> 24);
+ digest[j + 5] = (byte)(h >>> 16);
+ digest[j + 6] = (byte)(h >>> 8);
+ digest[j + 7] = (byte)(h );
+ }
+ }
+
+ /**
+ * Delivers string input data to the hashing algorithm.
+ *
+ * @param source plaintext data to hash (ASCII text string).
+ *
+ * This method maintains the invariant: bufferBits < 512
+ */
+ public void NESSIEadd(String source) {
+ if (source.length() > 0) {
+ byte[] data = new byte[source.length()];
+ for (int i = 0; i < source.length(); i++) {
+ data[i] = (byte)source.charAt(i);
+ }
+ NESSIEadd(data, 8*data.length);
+ }
+ }
+
+ static String display(byte[] array) {
+ char[] val = new char[2*array.length];
+ String hex = "0123456789ABCDEF";
+ for (int i = 0; i < array.length; i++) {
+ int b = array[i] & 0xff;
+ val[2*i] = hex.charAt(b >>> 4);
+ val[2*i + 1] = hex.charAt(b & 15);
+ }
+ return String.valueOf(val);
+ }
+
+ private static final int LONG_ITERATION = 100000000;
+
+ /**
+ * Generate the NESSIE test vector set for Whirlpool.
+ *
+ * The test consists of:
+ * 1. hashing all bit strings containing only zero bits
+ * for all lengths from 0 to 1023;
+ * 2. hashing all 512-bit strings containing a single set bit;
+ * 3. the iterated hashing of the 512-bit string of zero bits a large number of times.
+ */
+ public static void makeNESSIETestVectors() {
+ Whirlpool w = new Whirlpool();
+ byte[] digest = new byte[64];
+ byte[] data = new byte[128];
+ Arrays.fill(data, (byte)0);
+ System.out.println("Message digests of strings of 0-bits and length L:");
+ for (int i = 0; i < 1024; i++) {
+ w.NESSIEinit();
+ w.NESSIEadd(data, i);
+ w.NESSIEfinalize(digest);
+ String s = Integer.toString(i);
+ s = " ".substring(s.length()) + s;
+ System.out.println(" L =" + s + ": " + display(digest));
+ }
+ System.out.println("Message digests of all 512-bit strings S containing a single 1-bit:");
+ data = new byte[512/8];
+ Arrays.fill(data, (byte)0);
+ for (int i = 0; i < 512; i++) {
+ // set bit i:
+ data[i/8] |= 0x80 >>> (i % 8);
+ w.NESSIEinit();
+ w.NESSIEadd(data, 512);
+ w.NESSIEfinalize(digest);
+ System.out.println(" S = " + display(data) + ": " + display(digest));
+ // reset bit i:
+ data[i/8] = 0;
+ }
+ for (int i = 0; i < digest.length; i++) {
+ digest[i] = 0;
+ }
+ for (int i = 0; i < LONG_ITERATION; i++) {
+ w.NESSIEinit();
+ w.NESSIEadd(digest, 512);
+ w.NESSIEfinalize(digest);
+ }
+ System.out.println("Iterated message digest computation (" + LONG_ITERATION + " times): " + display(digest));
+ }
+
+ /**
+ * Generate the ISO/IEC 10118-3 test vector set for Whirlpool.
+ */
+ public static void makeISOTestVectors() {
+ Whirlpool w = new Whirlpool();
+ byte[] digest = new byte[DIGESTBYTES];
+ byte[] data = new byte[1000000];
+
+ Arrays.fill(data, (byte)0);
+
+ System.out.println("1. In this example the data-string is the empty string, i.e. the string of length zero.\n");
+ w.NESSIEinit();
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ System.out.println("2. In this example the data-string consists of a single byte, namely the ASCII-coded version of the letter 'a'.\n");
+ w.NESSIEinit();
+ w.NESSIEadd("a");
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ System.out.println("3. In this example the data-string is the three-byte string consisting of the ASCII-coded version of 'abc'.\n");
+ w.NESSIEinit();
+ w.NESSIEadd("abc");
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ System.out.println("4. In this example the data-string is the 14-byte string consisting of the ASCII-coded version of 'message digest'.\n");
+ w.NESSIEinit();
+ w.NESSIEadd("message digest");
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ System.out.println("5. In this example the data-string is the 26-byte string consisting of the ASCII-coded version of 'abcdefghijklmnopqrstuvwxyz'.\n");
+ w.NESSIEinit();
+ w.NESSIEadd("abcdefghijklmnopqrstuvwxyz");
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ System.out.println("6. In this example the data-string is the 62-byte string consisting of the ASCII-coded version of 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.\n");
+ w.NESSIEinit();
+ w.NESSIEadd("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ System.out.println("7. In this example the data-string is the 80-byte string consisting of the ASCII-coded version of eight repetitions of '1234567890'.\n");
+ w.NESSIEinit();
+ w.NESSIEadd("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ System.out.println("8. In this example the data-string is the 32-byte string consisting of the ASCII-coded version of 'abcdbcdecdefdefgefghfghighijhijk'.\n");
+ w.NESSIEinit();
+ w.NESSIEadd("abcdbcdecdefdefgefghfghighijhijk");
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+
+ Arrays.fill(data, (byte)'a');
+ System.out.println("9. In this example the data-string is the 1000000-byte string consisting of the ASCII-coded version of 'a' repeated 10^6 times.\n");
+ w.NESSIEinit();
+ w.NESSIEadd(data, 8*1000000);
+ w.NESSIEfinalize(digest);
+ System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
+ }
+
+ public static void main(String[] args) {
+ //makeNESSIETestVectors();
+ makeISOTestVectors();
+ }
+}
diff --git a/src/main/java/com/cypherx/xauth/xAuth.java b/src/main/java/com/cypherx/xauth/xAuth.java
new file mode 100644
index 0000000..89f8c91
--- /dev/null
+++ b/src/main/java/com/cypherx/xauth/xAuth.java
@@ -0,0 +1,600 @@
+//xAuth 1.2.2
+//Built against Bukkit #653, CraftBukkit #674, and Permissions v2.7
+
+package com.cypherx.xauth;
+
+import java.io.*;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.minecraft.server.PropertyManager;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.Event.Priority;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.plugin.PluginManager;
+
+import com.nijiko.permissions.PermissionHandler;
+import com.nijikokun.bukkit.Permissions.Permissions;
+
+/**
+ * xAuth for Bukkit
+ *
+ * @author CypherX
+ */
+public class xAuth extends JavaPlugin
+{
+ private final xAuthPlayerListener playerListener = new xAuthPlayerListener(this);
+ private final xAuthBlockListener blockListener = new xAuthBlockListener(this);
+ private final xAuthEntityListener entityListener = new xAuthEntityListener(this);
+ private static PluginDescriptionFile pdfFile;
+
+ private static final String DIR = "plugins" + File.separator + "xAuth" + File.separator;
+ private static final String CONFIG_FILE = "config.yml";
+ private static final String STRINGS_FILE = "strings.yml";
+ private static final String AUTH_FILE = "auths.txt";
+
+ public static Settings settings;
+ public static Strings strings;
+ public static PermissionHandler Permissions;
+
+ //autosave test code
+ private static Boolean fullyEnabled;
+
+ private ConcurrentHashMap auths = new ConcurrentHashMap();
+ private ConcurrentHashMap inventory = new ConcurrentHashMap();
+ private ConcurrentHashMap armor = new ConcurrentHashMap();
+ private ConcurrentHashMap sessions = new ConcurrentHashMap();
+ private ConcurrentHashMap lastNotifyTimes = new ConcurrentHashMap();
+ private ConcurrentHashMap strikes = new ConcurrentHashMap();
+ private ArrayList illegalNames = new ArrayList();
+
+ public void onEnable()
+ {
+ fullyEnabled = false;
+ pdfFile = this.getDescription();
+
+ PropertyManager props = new PropertyManager(new File("server.properties"));
+ if (props.a("online-mode", true))
+ {
+ System.out.println("[" + pdfFile.getName() + "] Stopping - Server is running in online-mode");
+ this.setEnabled(false);
+ this.getServer().getPluginManager().disablePlugin(this);
+ return;
+ }
+
+ File fDir = new File(DIR);
+
+ if (!fDir.exists())
+ fDir.mkdir();
+
+ try
+ {
+ File fAuths = new File(DIR + AUTH_FILE);
+
+ if (!fAuths.exists())
+ fAuths.createNewFile();
+ }
+ catch (Exception e)
+ {
+ System.out.println(e.getMessage());
+ }
+
+ settings = new Settings(new File(DIR + CONFIG_FILE));
+ strings = new Strings(new File(DIR + STRINGS_FILE));
+ getAuths();
+ setupPermissions();
+
+ //Hide inventory of any players online while server is starting (means /reload was used)
+ Player[] players = getServer().getOnlinePlayers();
+ if (players.length > 0)
+ {
+ for (Player player : players)
+ {
+ if (isRegistered(player.getName()))
+ {
+ saveInventory(player);
+ player.sendMessage(strings.getString("misc.reloaded"));
+ }
+ }
+ }
+
+ PluginManager pm = getServer().getPluginManager();
+ pm.registerEvent(Event.Type.PLAYER_CHAT, playerListener, Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_COMMAND_PREPROCESS, playerListener, Event.Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_DROP_ITEM, playerListener, Event.Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_PICKUP_ITEM, playerListener, Event.Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_INTERACT, playerListener, Event.Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_JOIN, playerListener, Event.Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_LOGIN, playerListener, Event.Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Event.Priority.Lowest, this);
+ pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener, Event.Priority.Lowest, this);
+
+ pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Lowest, this);
+ pm.registerEvent(Event.Type.BLOCK_PLACE, blockListener, Priority.Lowest, this);
+
+ pm.registerEvent(Event.Type.ENTITY_DAMAGE, entityListener, Priority.Lowest, this);
+ pm.registerEvent(Event.Type.ENTITY_TARGET, entityListener, Priority.Lowest, this);
+
+ System.out.println("[" + pdfFile.getName() + "]" + " v" + pdfFile.getVersion() + " Enabled!");
+
+ //autosave stuff
+ fullyEnabled = true;
+ }
+
+ public void getAuths()
+ {
+ System.out.println("[" + pdfFile.getName() + "] Loading player accounts..");
+
+ try
+ {
+ BufferedReader authReader = new BufferedReader(new FileReader(DIR + AUTH_FILE));
+
+ String line;
+ while ((line = authReader.readLine()) != null)
+ {
+ String[] split = line.split(":");
+ auths.put(split[0], line);
+ }
+ authReader.close();
+ System.out.print("[" + pdfFile.getName() + "] Done! Loaded " + auths.size() + " Accounts!");
+ }
+ catch (Exception e)
+ {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ public void onDisable()
+ {
+ getServer().getScheduler().cancelAllTasks();
+
+ //Restore players inventories so they are not lost
+ Player[] players = getServer().getOnlinePlayers();
+ if (players.length > 0)
+ {
+ for (Player player : players)
+ if (!sessionExists(player.getName()))
+ restoreInventory(player);
+ }
+
+ if (fullyEnabled)
+ updateAuthFile();
+
+ System.out.println("[" + pdfFile.getName() + "]" + " v" + pdfFile.getVersion() + " Disabled");
+ }
+
+ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args)
+ {
+ if (!this.isEnabled())
+ return false;
+
+ CommandHandler cmdHandler = new CommandHandler(this);
+
+ if (sender instanceof Player)
+ cmdHandler.handlePlayerCommand((Player)sender, cmd, args);
+ else if (sender instanceof ConsoleCommandSender)
+ cmdHandler.handleConsoleCommand(cmd, args);
+
+ return true;
+ }
+
+ //AUTH / REGISTER FUNCTIONS
+ public void addAuth(String pName, String pass)
+ {
+ String hash = whirlpool(pass);
+ auths.put(pName.toLowerCase(), pName.toLowerCase() + ":" + hash);
+
+ if (settings.getBool("misc.autosave"))
+ updateAuthFile();
+ }
+
+ public Boolean isRegistered(String pName)
+ {
+ if (auths.containsKey(pName.toLowerCase()))
+ return true;
+
+ return false;
+ }
+
+ public void changePass(String pName, String pass)
+ {
+ String hash = whirlpool(pass);
+
+ auths.remove(pName.toLowerCase());
+ auths.put(pName.toLowerCase(), pName.toLowerCase() + ":" + hash);
+
+ if (settings.getBool("misc.autosave"))
+ updateAuthFile();
+ }
+
+ public void removeAuth(String pName)
+ {
+ pName = pName.toLowerCase();
+ auths.remove(pName);
+
+ if (sessionExists(pName))
+ removeSession(pName);
+
+ if (settings.getBool("misc.autosave"))
+ updateAuthFile();
+ }
+
+ public void updateAuthFile()
+ {
+ try
+ {
+ BufferedWriter authWriter = new BufferedWriter(new FileWriter(DIR + AUTH_FILE));
+ for (String key: auths.keySet())
+ {
+ authWriter.write(auths.get(key));
+ authWriter.newLine();
+ }
+ authWriter.close();
+ }
+ catch (Exception e)
+ {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ public Boolean isValidPass(String pass)
+ {
+ if (!settings.getBool("password.complexity.enabled"))
+ {
+ if (pass.length() < settings.getInt("password.min-length"))
+ return false;
+
+ return true;
+ }
+
+ String pattern = "(";
+
+ if (settings.getBool("password.complexity.numbers"))
+ pattern += "(?=.*\\d)";
+
+ if (settings.getBool("password.complexity.lowercase"))
+ pattern += "(?=.*[a-z])";
+
+ if (settings.getBool("password.complexity.uppercase"))
+ pattern += "(?=.*[A-Z])";
+
+ if (settings.getBool("password.complexity.symbols"))
+ pattern += "(?=.*\\W)";
+
+ pattern += ".{" + settings.getInt("password.min-length") + ",})";
+
+ //String pattern = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\\W).{3,})";
+ Pattern p = Pattern.compile(pattern);
+ Matcher matcher = p.matcher(pass);
+ return matcher.matches();
+ }
+
+ //LOGIN / LOGOUT FUNCTIONS
+ public void login(Player player)
+ {
+ startSession(player);
+ restoreInventory(player);
+ }
+
+ public Boolean checkPass(Player player, String pass)
+ {
+ String account = auths.get(player.getName().toLowerCase());
+ int md5Length = player.getName().length() + 33;
+ String hash;
+
+ if (account.length() == md5Length)
+ hash = md5(pass);
+ else
+ hash = whirlpool(pass);
+
+ if (account.equals(player.getName().toLowerCase() + ":" + hash))
+ {
+ //change pass to whirlpool if md5
+ if (hash.length() == 32)
+ changePass(player.getName(), pass);
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ public void logout(Player player)
+ {
+ String pName = player.getName();
+
+ if (sessionExists(pName))
+ {
+ Session session = sessions.get(pName.toLowerCase());
+
+ if (session.isExpired(new Date(session.getLoginTime() + (settings.getInt("session.timeout") * 1000))))
+ removeSession(pName);
+ }
+ else
+ restoreInventory(player);
+ }
+
+ public void addStrike(Player player)
+ {
+ String addr = player.getAddress().getAddress().getHostAddress();
+ int newCount = 1;
+ if (strikes.containsKey(addr))
+ {
+ newCount = strikes.get(addr) + 1;
+ strikes.remove(addr);
+ }
+
+ strikes.put(addr, newCount);
+ }
+
+ public int getStrikes(Player player)
+ {
+ String addr = player.getAddress().getAddress().getHostAddress();
+
+ if (!strikes.containsKey(addr))
+ return 0;
+
+ return strikes.get(addr);
+ }
+
+ public void clearStrikes(Player player)
+ {
+ String addr = player.getAddress().getAddress().getHostAddress();
+ strikes.remove(addr);
+ }
+
+ //NOTIFY FUNCTIONS
+ public void handleEvent(Player player, Cancellable event)
+ {
+ if (!isRegistered(player.getName()) && !mustRegister(player))
+ return;
+
+ if (!sessionExists(player.getName()))
+ {
+ event.setCancelled(true);
+
+ if (canNotify(player))
+ notifyPlayer(player);
+ }
+ }
+
+ public Boolean isCmdAllowed(String cmd)
+ {
+ if (settings.getStrList("misc.allowed-cmds").contains(cmd))
+ return true;
+
+ return false;
+ }
+
+ public Boolean canNotify(Player player)
+ {
+ if (lastNotifyTimes.get(player) == null)
+ return true;
+
+ Date nextNotifyTime = new Date(lastNotifyTimes.get(player).getTime() + (settings.getInt("notify.limit") * 1000));
+ if (nextNotifyTime.compareTo(new Date()) < 0)
+ return true;
+
+ return false;
+ }
+
+ public void notifyPlayer(Player player)
+ {
+ player.sendMessage(strings.getString("misc.illegal"));
+ updateNotifyTime(player, new Date());
+ }
+
+ public void updateNotifyTime(Player player, Date date)
+ {
+ lastNotifyTimes.remove(player);
+ lastNotifyTimes.put(player, date);
+ }
+
+ //INVENTORY FUNCTIONS
+ public void saveInventory(Player player)
+ {
+ PlayerInventory playerInv = player.getInventory();
+ inventory.put(player, playerInv.getContents());
+ playerInv.clear();
+ armor.put(player, playerInv.getArmorContents());
+ playerInv.setHelmet(null);
+ playerInv.setChestplate(null);
+ playerInv.setLeggings(null);
+ playerInv.setBoots(null);
+ }
+
+ public void restoreInventory(Player player)
+ {
+ PlayerInventory playerInv = player.getInventory();
+
+ if (inventory.containsKey(player))
+ {
+ playerInv.setContents(inventory.get(player));
+ inventory.remove(player);
+ }
+
+ if (armor.containsKey(player))
+ {
+ playerInv.setBoots(armor.get(player)[0].getTypeId() == 0 ? null : armor.get(player)[0]);
+ playerInv.setLeggings(armor.get(player)[1].getTypeId() == 0 ? null : armor.get(player)[1]);
+ playerInv.setChestplate(armor.get(player)[2].getTypeId() == 0 ? null : armor.get(player)[2]);
+ playerInv.setHelmet(armor.get(player)[3].getTypeId() == 0 ? null : armor.get(player)[3]);
+ armor.remove(player);
+ }
+
+ player.saveData();
+ }
+
+ //SESSION FUNCTIONS
+ public void startSession(Player player)
+ {
+ sessions.put(player.getName().toLowerCase(), new Session(player));
+ }
+
+ public Boolean sessionExists(String pName)
+ {
+ if (sessions.containsKey(pName.toLowerCase()))
+ return true;
+
+ return false;
+ }
+
+ public Boolean isLoggedIn(Player player)
+ {
+ if (sessionExists(player.getName()))
+ {
+ if (isSessionValid(player))
+ return true;
+
+ removeSession(player.getName());
+ }
+
+ return false;
+ }
+
+ public Boolean isSessionValid(Player player)
+ {
+ Session session = sessions.get(player.getName().toLowerCase());
+ if (session.isExpired(new Date(session.getLoginTime() + (settings.getInt("session.timeout") * 1000))))
+ return false;
+
+ if (settings.getBool("session.verifyip") && !session.isValidAddr(player.getAddress().getAddress().getHostAddress()))
+ return false;
+
+ return true;
+ }
+
+ public void removeSession(String pName)
+ {
+ pName = pName.toLowerCase();
+ if (sessionExists(pName))
+ sessions.remove(pName);
+ }
+
+ public void killSession(Player player)
+ {
+ String pName = player.getName();
+ removeSession(pName);
+
+ if (player != null)
+ {
+ saveInventory(player);
+ player.sendMessage(strings.getString("logout.success.ended"));
+ }
+ }
+
+ //MISC FUNCTIONS
+ private void setupPermissions()
+ {
+ Plugin test = this.getServer().getPluginManager().getPlugin("Permissions");
+
+ if (xAuth.Permissions == null)
+ {
+ if (test != null)
+ xAuth.Permissions = ((Permissions)test).getHandler();
+ else
+ System.out.println("[" + pdfFile.getName() + "] Permissions plugin not detected, defaulting to ops.txt");
+ }
+ }
+
+ public String md5(String str)
+ {
+ try
+ {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] messageDigest = md.digest(str.getBytes());
+ BigInteger number = new BigInteger(1, messageDigest);
+ String hashtext = number.toString(16);
+ while (hashtext.length() < 32)
+ hashtext = "0" + hashtext;
+
+ return hashtext;
+ }
+ catch (Exception e)
+ {
+ System.out.println(e.getMessage());
+ }
+
+ return null;
+ }
+
+ public String whirlpool(String str)
+ {
+ Whirlpool w = new Whirlpool();
+ byte[] digest = new byte[Whirlpool.DIGESTBYTES];
+ w.NESSIEinit();
+ w.NESSIEadd(str);
+ w.NESSIEfinalize(digest);
+ return Whirlpool.display(digest);
+ }
+
+ public boolean canUseCommand(Player player, String node)
+ {
+ if (xAuth.Permissions == null)
+ {
+ if (!player.isOp())
+ return false;
+
+ return true;
+ }
+
+ if (!xAuth.Permissions.has(player, node))
+ return false;
+
+ return true;
+ }
+
+ public Boolean isNameLegal(String pName)
+ {
+ pName = pName.toLowerCase();
+
+ if (illegalNames.contains(pName))
+ return false;
+
+ String allowed = settings.getStr("filter.allowed");
+
+ for(int i = 0; i < pName.length(); i++)
+ if (allowed.indexOf(pName.charAt(i)) == -1)
+ {
+ illegalNames.add(pName);
+ return false;
+ }
+
+ return true;
+ }
+
+ public void reload()
+ {
+ updateAuthFile();
+ settings = new Settings(new File(DIR + CONFIG_FILE));
+ strings = new Strings(new File(DIR + STRINGS_FILE));
+ getAuths();
+ System.out.println("[" + pdfFile.getName() + "] Configuration & Accounts reloaded");
+ }
+
+ public Boolean mustRegister(Player player)
+ {
+ if (!settings.getBool("registration.forced"))
+ return false;
+
+ if (xAuth.Permissions != null)
+ if (xAuth.Permissions.has(player, "xauth.exclude"))
+ return false;
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/cypherx/xauth/xAuthBlockListener.java b/src/main/java/com/cypherx/xauth/xAuthBlockListener.java
new file mode 100644
index 0000000..18e7937
--- /dev/null
+++ b/src/main/java/com/cypherx/xauth/xAuthBlockListener.java
@@ -0,0 +1,38 @@
+package com.cypherx.xauth;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.block.*;
+
+/**
+ * Handle events for all Block related events
+ * @author CypherX
+ */
+public class xAuthBlockListener extends BlockListener
+{
+ private final xAuth plugin;
+
+ public xAuthBlockListener(final xAuth plugin)
+ {
+ this.plugin = plugin;
+ }
+
+ //Prevents players from breaking blocks
+ public void onBlockBreak(BlockBreakEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Player player = event.getPlayer();
+ plugin.handleEvent(player, event);
+ }
+
+ //Prevents player from placing blocks
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Player player = event.getPlayer();
+ plugin.handleEvent(player, event);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/cypherx/xauth/xAuthEntityListener.java b/src/main/java/com/cypherx/xauth/xAuthEntityListener.java
new file mode 100644
index 0000000..a008cec
--- /dev/null
+++ b/src/main/java/com/cypherx/xauth/xAuthEntityListener.java
@@ -0,0 +1,51 @@
+package com.cypherx.xauth;
+
+import org.bukkit.entity.*;
+import org.bukkit.event.entity.*;
+
+/**
+ * Handle events for all Entity related events
+ * @author CypherX
+ */
+public class xAuthEntityListener extends EntityListener
+{
+ private final xAuth plugin;
+
+ public xAuthEntityListener(final xAuth plugin)
+ {
+ this.plugin = plugin;
+ }
+
+ //Prevents player from taking damage or giving damage
+ public void onEntityDamage(EntityDamageEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Entity entity = event.getEntity();
+
+ //Player taking damage
+ if (entity instanceof Player)
+ plugin.handleEvent((Player)entity, event);
+ //Player dealing damage to other entity
+ else if (event instanceof EntityDamageByEntityEvent)
+ {
+ EntityDamageByEntityEvent edbeEvent = (EntityDamageByEntityEvent)event;
+ Entity damager = edbeEvent.getDamager();
+
+ if (damager instanceof Player)
+ plugin.handleEvent((Player)damager, event);
+ }
+ }
+
+ //Prevents monsters from attacking player
+ public void onEntityTarget(EntityTargetEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Entity entity = event.getTarget();
+ if (entity instanceof Player)
+ plugin.handleEvent((Player)entity, event);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/cypherx/xauth/xAuthPlayerListener.java b/src/main/java/com/cypherx/xauth/xAuthPlayerListener.java
new file mode 100644
index 0000000..7905a69
--- /dev/null
+++ b/src/main/java/com/cypherx/xauth/xAuthPlayerListener.java
@@ -0,0 +1,146 @@
+package com.cypherx.xauth;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.*;
+
+/**
+ * Handle events for all Player related events
+ * @author CypherX
+ */
+public class xAuthPlayerListener extends PlayerListener
+{
+ private final xAuth plugin;
+
+ public xAuthPlayerListener(final xAuth instance)
+ {
+ plugin = instance;
+ }
+
+ public void onPlayerLogin(PlayerLoginEvent event)
+ {
+ Player player = event.getPlayer();
+
+ if (player.isOnline())
+ event.disallow(PlayerLoginEvent.Result.KICK_OTHER, "A player with this name is already online.");
+
+ if (xAuth.settings.getBool("filter.enabled") && !plugin.isNameLegal(player.getName()))
+ event.disallow(PlayerLoginEvent.Result.KICK_OTHER, xAuth.strings.getString("misc.filterkickmsg"));
+
+ if (xAuth.settings.getBool("filter.block-blankname") && player.getName().trim().equals(""))
+ event.disallow(PlayerLoginEvent.Result.KICK_OTHER, xAuth.strings.getString("misc.blankkickmsg"));
+ }
+
+ public void onPlayerJoin(PlayerJoinEvent event)
+ {
+ final Player player = event.getPlayer();
+
+ if (!plugin.isLoggedIn(player))
+ {
+ if (!plugin.isRegistered(player.getName()))
+ {
+ if (!plugin.mustRegister(player))
+ return;
+
+ plugin.saveInventory(player);
+ plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
+ public void run() {
+ player.sendMessage(xAuth.strings.getString("register.login"));
+ }
+ }, 5);
+ }
+ else
+ {
+ plugin.saveInventory(player);
+ plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
+ public void run() {
+ player.sendMessage(xAuth.strings.getString("login.login"));
+ }
+ }, 5);
+ }
+ }
+ }
+
+ public void onPlayerQuit(PlayerQuitEvent event)
+ {
+ plugin.logout(event.getPlayer());
+ }
+
+ //Prevents players from executing commands
+ public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Player player = event.getPlayer();
+ String[] msg = event.getMessage().split(" ");
+
+ if (!plugin.isCmdAllowed(msg[0]))
+ plugin.handleEvent(player, event);
+
+ if (event.isCancelled())
+ event.setMessage("/");
+ }
+
+ //Prevents player from being able to chat
+ public void onPlayerChat(PlayerChatEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Player player = event.getPlayer();
+ plugin.handleEvent(player, event);
+ }
+
+ //Prevents player from being able to drop an item (inventory should be empty anyway)
+ public void onPlayerDropItem(PlayerDropItemEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Player player = event.getPlayer();
+ plugin.handleEvent(player, event);
+ }
+
+ public void onPlayerInteract(PlayerInteractEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Player player = event.getPlayer();
+ plugin.handleEvent(player, event);
+ }
+
+ //Prevents player from moving
+ public void onPlayerMove(PlayerMoveEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Location from = event.getFrom();
+ Location to = event.getTo();
+
+ if (from.getX() == to.getX() && from.getZ() == to.getZ())
+ {
+ if (from.getY() > to.getY())
+ return;
+ }
+
+ Player player = event.getPlayer();
+ plugin.handleEvent(player, event);
+
+ if (event.isCancelled())
+ player.teleport(event.getFrom());
+ //player.teleportTo(event.getFrom());
+ }
+
+ //Prevents player from picking up items
+ public void onPlayerPickupItem(PlayerPickupItemEvent event)
+ {
+ if (event.isCancelled())
+ return;
+
+ Player player = event.getPlayer();
+ plugin.handleEvent(player, event);
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..e682d11
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,29 @@
+name: xAuth
+main: com.cypherx.xauth.xAuth
+version: 1.2.2
+description: Allows players to register and maintain an account while the server is in offline-mode.
+authors:
+ - CypherX
+
+commands:
+ register:
+ description: Register your player name
+ usage: /register
+ login:
+ description: Authenticate yourself
+ usage: /login
+ changepw:
+ description: Change your or another players password
+ usage: /changepw [player]
+ unregister:
+ description: Remove a players registration
+ usage: /unregister
+ authreload:
+ description: Reload the account, configuration, and string files
+ usage: /authreload
+ toggle:
+ description: Toggle various commands on/off
+ usage: /toggle
+ logout:
+ description: End a players session and force them to re-authenticate
+ usage: /logout [player]
\ No newline at end of file