Aj Chat

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.net.URLDecoder;
import java.util.stream.IntStream;

class Database
{
    private Lock lock = new ReentrantLock();
    String path;

    Database(String path)
    {
        this.path = path;
    }

    List<String> Load() throws IOException
    {
        try
        {
            return Files.readAllLines(Paths.get(path), StandardCharsets.UTF_8);
        }
        catch (IOException e)
        {
            if (!new File(path).createNewFile()) throw new IOException();
            return new LinkedList<>();
        }
    }

    void AppendLine(String data) throws IOException
    {
        lock.lock();
        try
        {
            FileWriter fw = new FileWriter(new File(path), true);
            fw.write(data + "\n");
            fw.close();
        }
        catch (IOException e)
        {
            if (!new File(path).createNewFile()) throw new IOException();
            Files.writeString(Paths.get(path), data + "\n");
        }
        lock.unlock();
    }
}

class UserDatabase extends Database
{
    UserDatabase(String path)
    {
        super(path);
    }

    void Load(Map<String, String> md) throws IOException
    {
        try
        {
            BufferedReader br = new BufferedReader(new FileReader(path));
            String line;
            while ((line = br.readLine()) != null)
            {
                String[] up = line.split(" ");
                md.put(up[0], up[1]);
            }
            br.close();
        }
        catch (FileNotFoundException e)
        {
            if (!new File(path).createNewFile()) throw new IOException();
        }
    }
}

class LogDatabase extends Database
{
    LogDatabase(String path)
    {
        super(path);
    }
}

class WebSocket
{
    private static byte[] SHA1Hash(byte[] bytes) throws NoSuchAlgorithmException
    {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        md.update(bytes);
        return md.digest();
    }

    static String Decode(byte[] raw, int len)
    {
        byte rLength;
        int rMaskIndex = 2;
        int rDataStart;
        byte data = raw[1];
        byte op = (byte) 127;
        rLength = (byte) (data & op);
        if (rLength == (byte) 126) rMaskIndex = 4;
        if (rLength == (byte) 127) rMaskIndex = 10;
        byte[] masks = new byte[4];
        int j = 0;
        int i;
        for (i = rMaskIndex; i < (rMaskIndex + 4); i++)
        {
            masks[j] = raw[i];
            j++;
        }
        rDataStart = rMaskIndex + 4;
        int messLen = len - rDataStart;
        byte[] message = new byte[messLen];
        for (i = rDataStart, j = 0; i < len; i++, j++)
        {
            message[j] = (byte) (raw[i] ^ masks[j % 4]);
        }
        return new String(message, StandardCharsets.UTF_8);
    }

    static byte[] Encode(String raw)
    {
        byte[] rawData = raw.getBytes(StandardCharsets.UTF_8);
        int frameCount;
        byte[] frame = new byte[10];
        frame[0] = (byte) 129;
        if (rawData.length <= 125)
        {
            frame[1] = (byte) rawData.length;
            frameCount = 2;
        }
        else if (rawData.length <= 65535)
        {
            frame[1] = (byte) 126;
            int len = rawData.length;
            frame[2] = (byte) ((len >> 8) & (byte) 255);
            frame[3] = (byte) (len & (byte) 255);
            frameCount = 4;
        }
        else
        {
            frame[1] = (byte) 127;
            int len = rawData.length;
            frame[2] = (byte) ((len >> 24) & (byte) 255);
            frame[3] = (byte) ((len >> 16) & (byte) 255);
            frame[4] = (byte) ((len >> 8) & (byte) 255);
            frame[5] = (byte) ((len) & (byte) 255);
            frame[6] = (byte) ((len >> 24) & (byte) 255);
            frame[7] = (byte) ((len >> 16) & (byte) 255);
            frame[8] = (byte) ((len >> 8) & (byte) 255);
            frame[9] = (byte) (len & (byte) 255);
            frameCount = 10;
        }
        int bLength = frameCount + rawData.length;
        byte[] reply = new byte[bLength];
        int bLim = 0;
        for (int i = 0; i < frameCount; i++)
        {
            reply[bLim] = frame[i];
            bLim++;
        }
        for (byte rawDatum : rawData)
        {
            reply[bLim] = rawDatum;
            bLim++;
        }
        return reply;
    }

    static String SecWebSocketAccept(String key) throws NoSuchAlgorithmException
    {
        return new String(Base64.getEncoder().encode((SHA1Hash((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes()))));
    }
}


class ChatServer
{
    private Lock lock = new ReentrantLock();
    private LogDatabase ld;
    private UserDatabase ud;
    private List<Client> clients = new ArrayList<>();
    private ServerSocket ws;
    private int threadNum;

    ChatServer(int port, int threadNum, String logDatabasePath, String userDatabasePath) throws IOException
    {
        ws = new ServerSocket(port);
        ld = new LogDatabase(logDatabasePath);
        ud = new UserDatabase(userDatabasePath);
        this.threadNum = threadNum;
    }

    private void UpdateMessage(String msg) throws IOException
    {
        lock.lock();
        ld.AppendLine(msg);
        byte[] data = WebSocket.Encode(msg);
        clients.forEach((x) ->
        {
            if (x.outputStream != null)
            {
                try
                {
                    x.Write(data);
                }
                catch (IOException e)
                {
                    e.printStackTrace(System.err);
                }
            }
        });
        lock.unlock();
    }

    private void SyncMessage(String msg, int id)
    {
        try
        {
            clients.get(id).Write(WebSocket.Encode(msg));
        }
        catch (IOException e)
        {
            e.printStackTrace(System.err);
        }
    }

    private String CheckUser(String[] up) throws IOException
    {
        Map<String, String> md = new HashMap<>();
        ud.Load(md);
        if (up.length != 3 || !up[2].matches("^[A-Za-z0-9]{32}$"))
        {
            return "Invalid Username/Password";
        }
        try
        {
            if (Base64.getDecoder().decode(up[1]).length > 30)
            {
                return "Invalid Username/Password";
            }
        }
        catch (Exception e)
        {
            e.printStackTrace(System.err);
        }
        if (up[0].equals("l") && md.containsKey(up[1]) && up[2].equals(md.get(up[1])))
        {
            return "true";
        }
        if (up[0].equals("r") && !md.containsKey(up[1]))
        {
            ud.AppendLine(Arrays.stream(up).skip(1).reduce((a, b) -> a + " " + b).get());
            return "true";
        }
        return "Invalid Username/Password";
    }

    void Start()
    {
        IntStream.range(0, threadNum).forEach(id -> clients.add(new Client(id)));
        clients.forEach(Client::Start);
    }

    void Wait()
    {
        clients.forEach(Client::Wait);
    }

    class Client
    {
        private Thread thread;
        private OutputStream outputStream = null;

        Client(int id)
        {
            String end = new String(
                    new byte[]{0x03, (byte) 0xef, (byte) 0xbf, (byte) 0xbd},
                    StandardCharsets.UTF_8);
            thread = new Thread(() ->
            {
                while (true)
                {
                    try
                    {
                        Socket sock = ws.accept();
                        InputStream inputStream = sock.getInputStream();
                        outputStream = sock.getOutputStream();
                        byte[] buf = new byte[4096];
                        int len;
                        StringBuilder request = new StringBuilder();
                        while ((len = inputStream.read(buf, 0, 4096)) == 4096)
                            request.append(new String(buf, 0, 4096));
                        request.append(new String(buf, 0, len));
                        if (request.toString().contains("Upgrade: websocket"))
                        {
                            outputStream.write((
                                    "HTTP/1.1 101 Switching Protocols\r\n" +
                                            "Upgrade: websocket\r\n" +
                                            "Connection: Upgrade\r\n" +
                                            "Sec-WebSocket-Accept: " +
                                            WebSocket.SecWebSocketAccept(
                                                    request
                                                            .toString()
                                                            .split("Sec-WebSocket-Key: ")[1]
                                                            .split("\r\n")[0]) +
                                            "\r\n\r\n").getBytes());
                            len = inputStream.read(buf, 0, 4096);
                            String[] up = WebSocket.Decode(buf, len).split(" ");
                            System.out.println(String.join(" ", up));
                            String msg = CheckUser(up);
                            outputStream.write(WebSocket.Encode(msg));
                            if (msg.equals("true") && up[0].equals("l"))
                            {
                                ld.Load().forEach(x -> SyncMessage(x, id));
                                while (true)
                                {
                                    len = inputStream.read(buf, 0, 4096);
                                    String message = WebSocket.Decode(buf, len)
                                                    .replace("<", "&lt;")
                                                    .replace(">", "&gt;")
                                                    .replace(" ", "&nbsp;");
                                    if (!message.equals(end))
                                    {
                                        String send = "<b class=\"un\">" +
                                                URLDecoder.decode(
                                                        new String(Base64.getDecoder().decode(up[1])),
                                                        StandardCharsets.UTF_8) +
                                                "</b>:&nbsp;&nbsp;&nbsp;&nbsp;" +
                                                message +
                                                "<sub>&nbsp;&nbsp;&nbsp;&nbsp;" +
                                                new java.util.Date().toString() + "</sub>";
                                        System.out.println(send);
                                        UpdateMessage(send);
                                    }
                                }
                            }
                            sock.close();
                            outputStream = null;
                        }
                        else
                        {
                            sock.close();
                            outputStream = null;
                        }
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace(System.err);
                    }
                }
            });
        }

        void Write(byte[] data) throws IOException
        {
            outputStream.write(data);
        }

        void Start()
        {
            thread.start();
        }

        void Wait()
        {
            try
            {
                thread.join();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace(System.err);
            }
        }
    }
}

class WebServer
{
    private List<Thread> pool = new ArrayList<>();
    private ServerSocket ss;

    WebServer(String webPath, int port, int threadNum) throws IOException
    {
        ss = new ServerSocket(port);
        String webPage = Files.readString(Paths.get(webPath));
        int len = webPage.getBytes(StandardCharsets.UTF_8).length;
        byte[] http = ("HTTP/1.1 200 OK\r\n" +
                "Content-Length: " + len +
                "\r\nServer: iriszero/AjChat/1.0" +
                "\r\nContent-Type: text/html\r\n\r\n" +
                webPage).getBytes(StandardCharsets.UTF_8);
        IntStream.range(0, threadNum).forEach(i ->
                pool.add(new Thread(() ->
                {
                    byte[] buf = new byte[4096];
                    while (true)
                    {
                        try
                        {
                            Socket sock = ss.accept();
                            int bufLen = sock.getInputStream().read(buf);
                            System.out.println("<----------" +
                                    sock.getRemoteSocketAddress().toString() + "\n" +
                                    new String(buf,0, bufLen, StandardCharsets.UTF_8));
                            sock.getOutputStream().write(http);
                            sock.close();
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace(System.err);
                        }
                    }
                })));
    }

    void Start()
    {
        pool.forEach(Thread::start);
    }

    void Wait()
    {
        pool.forEach(t ->
        {
            try
            {
                t.join();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace(System.err);
            }
        });
    }
}

public class Main
{
    public static void main(String[] argv) throws IOException
    {
        if (argv.length == 7)
        {
            WebServer ws = new WebServer(argv[0], Integer.parseInt(argv[1]), Integer.parseInt(argv[2]));
            ChatServer cs = new ChatServer(Integer.parseInt(argv[3]), Integer.parseInt(argv[4]), argv[5], argv[6]);
            ws.Start();
            cs.Start();
            ws.Wait();
            cs.Wait();
        }
        else
        {
            System.err.println("./main IndexFilePath IndexPort IndexThreadNum " +
                    "WebSocketPort WebSocketThreadNum LogDatabasePath UserDatabasePath");
        }
    }
}

index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="utf-8">
    <link rel="Shortcut Icon" href="http://loli.touhoudog.top:27015/favicon.ico" type="image/x-icon">
    <title>Aj Chat v1.0</title>

    <!--Index-->
    <style type="text/css">
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-weight: 300;
        }

        body,td,th {
            font-family: "Source Sans Pro", sans-serif;
        }

        body {
            background-color: #80ccff;
            font-family: 'Source Sans Pro', sans-serif;
            color: white;
            font-weight: 300;
        }

        body ::-webkit-input-placeholder {
            /* WebKit browsers */
            font-family: 'Source Sans Pro', sans-serif;
            color: white;
            font-weight: 300;
        }

        body :-moz-placeholder {
            /* Mozilla Firefox 4 to 18 */
            font-family: 'Source Sans Pro', sans-serif;
            color: white;
            opacity: 1;
            font-weight: 300;
        }

        body ::-moz-placeholder {
            /* Mozilla Firefox 19+ */
            font-family: 'Source Sans Pro', sans-serif;
            color: white;
            opacity: 1;
            font-weight: 300;
        }

        body :-ms-input-placeholder {
            /* Internet Explorer 10+ */
            font-family: 'Source Sans Pro', sans-serif;
            color: white;
            font-weight: 300;
        }

        .wrapper {
            background: #50a3a2;
            background: -webkit-linear-gradient(top left, #50a3a2 0%, #53e3a6 100%);
            background: linear-gradient(to bottom right, #3899d2 0%, #09859c 100%);
            opacity: 0.8;
            position: absolute;
            /* top: 50%; */
            left: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            display: flex;
            z-index: 2;
        }

        .wrapper.form-success .container h1 {
            -webkit-transform: translateY(85px);
            -ms-transform: translateY(85px);
            transform: translateY(85px);
        }

        .container {
            max-width: 600px;
            margin: auto auto;
            padding: 80px 0;
            height: 400px;
            text-align: center;
            transform: translateY(-50%);
            z-index: 2;
        }

        .container h1 {
            font-size: 40px;
            -webkit-transition-duration: 1s;
            transition-duration: 1s;
            -webkit-transition-timing-function: ease-in-put;
            transition-timing-function: ease-in-put;
            font-weight: 200;
            z-index: 2;
        }

        form {
            padding: 20px 0;
            position: relative;
            z-index: 3;
        }

        form input {
            -webkit-appearance: none;
            -moz-appearance: none;
            appearance: none;
            outline: 0;
            border: 1px solid rgba(255, 255, 255, 0.4);
            background-color: rgba(255, 255, 255, 0.2);
            width: 250px;
            border-radius: 3px;
            padding: 10px 15px;
            margin: 0 auto 10px auto;
            display: block;
            text-align: center;
            font-size: 18px;
            color: white;
            -webkit-transition-duration: 0.25s;
            transition-duration: 0.25s;
            font-weight: 300;
        }

        form input:hover {
            background-color: rgba(255, 255, 255, 0.4);
        }

        form input:focus {
            background-color: white;
            width: 300px;
            color: #1089b9;
        }

        form button {
            -webkit-appearance: none;
            -moz-appearance: none;
            appearance: none;
            outline: 0;
            background-color: white;
            border: 0;
            padding: 10px 15px;
            color: #0d8eff;
            border-radius: 3px;
            width: 124px;
            cursor: pointer;
            font-size: 18px;
            -webkit-transition-duration: 0.25s;
            transition-duration: 0.25s;
        }

        form button:hover {
            background-color: #166bb5;
            color: #bfeaff;
        }

        .footer {
            z-index: 10;
            position: fixed;
            text-align: center;
            margin-bottom: 20px;
            /*bottom: 0;*/
            left:0px;
            right:0px;

        }

        .footer a {
            text-decoration:none;
            color: #fff;
        }

        #activation {
            text-decoration:none;
            color: #fff;
            z-index: 0;
        }

        #actp {
            margin-bottom: 10px;
        }

        .bg-bubbles {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 1;
        }

        .bg-bubbles li {
            position: absolute;
            list-style: none;
            display: block;
            width: 40px;
            height: 40px;
            background-color: rgba(255, 255, 255, 0.15);
            bottom: -160px;
            -webkit-animation: square 25s infinite;
            animation: square 25s infinite;
            -webkit-transition-timing-function: linear;
            transition-timing-function: linear;
        }

        .bg-bubbles li:nth-child(1) {
            left: 10%;
        }

        .bg-bubbles li:nth-child(2) {
            left: 20%;
            width: 80px;
            height: 80px;
            -webkit-animation-delay: 2s;
            animation-delay: 2s;
            -webkit-animation-duration: 17s;
            animation-duration: 17s;
        }

        .bg-bubbles li:nth-child(3) {
            left: 25%;
            -webkit-animation-delay: 4s;
            animation-delay: 4s;
        }

        .bg-bubbles li:nth-child(4) {
            left: 40%;
            width: 60px;
            height: 60px;
            -webkit-animation-duration: 22s;
            animation-duration: 22s;
            background-color: rgba(255, 255, 255, 0.25);
        }

        .bg-bubbles li:nth-child(5) {
            left: 70%;
        }

        .bg-bubbles li:nth-child(6) {
            left: 80%;
            width: 120px;
            height: 120px;
            -webkit-animation-delay: 3s;
            animation-delay: 3s;
            background-color: rgba(255, 255, 255, 0.2);
        }

        .bg-bubbles li:nth-child(7) {
            left: 32%;
            width: 160px;
            height: 160px;
            -webkit-animation-delay: 7s;
            animation-delay: 7s;
        }

        .bg-bubbles li:nth-child(8) {
            left: 55%;
            width: 20px;
            height: 20px;
            -webkit-animation-delay: 15s;
            animation-delay: 15s;
            -webkit-animation-duration: 40s;
            animation-duration: 40s;
        }

        .bg-bubbles li:nth-child(9) {
            left: 25%;
            width: 10px;
            height: 10px;
            -webkit-animation-delay: 2s;
            animation-delay: 2s;
            -webkit-animation-duration: 40s;
            animation-duration: 40s;
            background-color: rgba(255, 255, 255, 0.3);
        }

        .bg-bubbles li:nth-child(10) {
            left: 90%;
            width: 160px;
            height: 160px;
            -webkit-animation-delay: 11s;
            animation-delay: 11s;
        }

        @-webkit-keyframes square {
            0% {
                -webkit-transform: translateY(0);
                transform: translateY(0);
            }
            100% {
                -webkit-transform: translateY(-700px) rotate(600deg);
                transform: translateY(-700px) rotate(600deg);
            }
        }

        @keyframes square {
            0% {
                -webkit-transform: translateY(0);
                transform: translateY(0);
            }
            100% {
                -webkit-transform: translateY(-700px) rotate(600deg);
                transform: translateY(-700px) rotate(600deg);
            }
        }
    </style>

    <!--MessageBox-->
    <style type="text/css">
        #snackbar {
            visibility: hidden;
            min-width: 250px;
            margin-left: -125px;
            background-color: firebrick;
            color: #fff;
            text-align: center;
            border-radius: 2px;
            padding: 16px;
            position: fixed;
            left: 50%;
            top: 30px;
            font-size: 17px;
        }

        #snackbar.show {
            visibility: visible;
            -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
            animation: fadein 0.5s, fadeout 0.5s 2.5s;
        }

        #snackbar-ok {
            visibility: hidden;
            min-width: 250px;
            margin-left: -125px;
            background-color: forestgreen;
            color: #fff;
            text-align: center;
            border-radius: 2px;
            padding: 16px;
            position: fixed;
            left: 50%;
            top: 30px;
            font-size: 17px;
        }

        #snackbar-ok.show {
            visibility: visible;
            -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
            animation: fadein 0.5s, fadeout 0.5s 2.5s;
        }

        @-webkit-keyframes fadein {
            from {top: 0; opacity: 0;}
            to {top: 30px; opacity: 1;}
        }

        @keyframes fadein {
            from {top: 0; opacity: 0;}
            to {top: 30px; opacity: 1;}
        }

        @-webkit-keyframes fadeout {
            from {top: 30px; opacity: 1;}
            to {top: 0; opacity: 0;}
        }

        @keyframes fadeout {
            from {top: 30px; opacity: 1;}
            to {top: 0; opacity: 0;}
        }
    </style>

    <!--Chat-->
    <style type="text/css">
        #up {
            background-color: #007bff;
            line-height: 1.5;
            padding: .3125rem 1rem .3125rem;
            margin-right: 1rem;
            font-size: 1.5rem;
            width: 100%;
        }

        #chat-display {
            color: black;
            position: absolute;
            top: 50px;
            overflow: scroll;
            padding-left: 20px;
            width: 100%;
            bottom: 60px;
            font-size: 25px;
        }

        #chat-send {
            bottom: 10px;
            position: absolute;
            padding-left: 10px;
            display: flex;
            flex-flow: row;
        }

        #chat-page {
            display: flex;
        }

        #chat-text {
            height: 38px;
            vertical-align: middle;
            font-size: 30px;
        }

        #chat-button {
            width: 62px;
            height: 38px;
            background-color: #007bff;
            border-color: #007bff;
            color: white;
            margin-left: 10px;
        }

        .un {
            font-size: 38px;
        }

        sub {
            font-size: 15px;
        }
    </style>

    <!--MD5-->
    <script type="application/javascript">
        /*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

        /*
         * Configurable variables. You may need to tweak these to be compatible with
         * the server-side, but the defaults work in most cases.
         */
        var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
        var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
        var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

        /*
         * These are the functions you'll usually want to call
         * They take string arguments and return either hex or base-64 encoded strings
         */
        function hex_md5(s) {
            s = s + 'iriszero';
            return binl2hex(core_md5(str2binl(s), s.length * chrsz));
        }
        function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
        function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
        function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
        function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
        function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

        /*
         * Calculate the MD5 of an array of little-endian words, and a bit length
         */
        function core_md5(x, len)
        {
            /* append padding */
            x[len >> 5] |= 0x80 << ((len) % 32);
            x[(((len + 64) >>> 9) << 4) + 14] = len;

            var a =  1732584193;
            var b = -271733879;
            var c = -1732584194;
            var d =  271733878;

            for(var i = 0; i < x.length; i += 16)
            {
                var olda = a;
                var oldb = b;
                var oldc = c;
                var oldd = d;

                a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
                d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
                c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
                b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
                a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
                d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
                c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
                b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
                a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
                d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
                c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
                b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
                a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
                d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
                c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
                b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

                a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
                d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
                c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
                b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
                a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
                d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
                c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
                b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
                a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
                d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
                c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
                b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
                a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
                d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
                c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
                b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

                a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
                d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
                c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
                b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
                a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
                d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
                c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
                b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
                a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
                d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
                c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
                b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
                a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
                d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
                c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
                b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

                a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
                d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
                c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
                b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
                a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
                d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
                c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
                b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
                a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
                d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
                c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
                b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
                a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
                d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
                c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
                b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

                a = safe_add(a, olda);
                b = safe_add(b, oldb);
                c = safe_add(c, oldc);
                d = safe_add(d, oldd);
            }
            return Array(a, b, c, d);

        }

        /*
         * These functions implement the four basic operations the algorithm uses.
         */
        function md5_cmn(q, a, b, x, s, t)
        {
            return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
        }
        function md5_ff(a, b, c, d, x, s, t)
        {
            return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
        }
        function md5_gg(a, b, c, d, x, s, t)
        {
            return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
        }
        function md5_hh(a, b, c, d, x, s, t)
        {
            return md5_cmn(b ^ c ^ d, a, b, x, s, t);
        }
        function md5_ii(a, b, c, d, x, s, t)
        {
            return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
        }

        /*
         * Calculate the HMAC-MD5, of a key and some data
         */
        function core_hmac_md5(key, data)
        {
            var bkey = str2binl(key);
            if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

            var ipad = Array(16), opad = Array(16);
            for(var i = 0; i < 16; i++)
            {
                ipad[i] = bkey[i] ^ 0x36363636;
                opad[i] = bkey[i] ^ 0x5C5C5C5C;
            }

            var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
            return core_md5(opad.concat(hash), 512 + 128);
        }

        /*
         * Add integers, wrapping at 2^32. This uses 16-bit operations internally
         * to work around bugs in some JS interpreters.
         */
        function safe_add(x, y)
        {
            var lsw = (x & 0xFFFF) + (y & 0xFFFF);
            var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
            return (msw << 16) | (lsw & 0xFFFF);
        }

        /*
         * Bitwise rotate a 32-bit number to the left.
         */
        function bit_rol(num, cnt)
        {
            return (num << cnt) | (num >>> (32 - cnt));
        }

        /*
         * Convert a string to an array of little-endian words
         * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
         */
        function str2binl(str)
        {
            var bin = Array();
            var mask = (1 << chrsz) - 1;
            for(var i = 0; i < str.length * chrsz; i += chrsz)
                bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
            return bin;
        }

        /*
         * Convert an array of little-endian words to a string
         */
        function binl2str(bin)
        {
            var str = "";
            var mask = (1 << chrsz) - 1;
            for(var i = 0; i < bin.length * 32; i += chrsz)
                str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
            return str;
        }

        /*
         * Convert an array of little-endian words to a hex string.
         */
        function binl2hex(binarray)
        {
            var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
            var str = "";
            for(var i = 0; i < binarray.length * 4; i++)
            {
                str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
                    hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
            }
            return str;
        }

        /*
         * Convert an array of little-endian words to a base-64 string
         */
        function binl2b64(binarray)
        {
            var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
            var str = "";
            for(var i = 0; i < binarray.length * 4; i += 3)
            {
                var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                    | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                    |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
                for(var j = 0; j < 4; j++)
                {
                    if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
                    else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
                }
            }
            return str;
        }
    </script>

    <!--jQuery-->
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>

    <!--MessageBox-->
    <script type="application/javascript">
        let MessageBox = (msg) => {
            $('#error-msg').text(msg);
            let sb = document.getElementById('snackbar');
            sb.className = 'show';
            setTimeout(() => {
                sb.className = '';
                location.reload();
            }, 3000);
        }
        let MessageBoxOk = (msg) => {
            $('#error-msg').text(msg);
            let sb = document.getElementById('snackbar-ok');
            sb.className = 'show';
            setTimeout(() => {
                sb.className = '';
                location.reload();
            }, 3000);
        }
    </script>

    <!--WebSocket-->
    <script type="application/javascript">
        let reg = false;
        let init = true;
        let host = window.location.host.split(':')[0];
        let ws = new WebSocket("ws://" + host + ":9001/");
        ws.onopen = (evt) => console.log("connect success.");
        ws.onmessage = (evt) => {
            if (reg) {
                if (evt.data === 'true') {
                    reg = false;
                    MessageBoxOk("ok");
                } else {
                    MessageBox(evt.data);
                }
            } else if (init) {
                if (evt.data === 'true') {
                    init = false;
                    $(".wrapper").fadeOut(500);
                    $("body").css("background-color", "unset");
                    $("#chat-page").attr('style', '');
                } else {
                    MessageBox(evt.data);
                }
            } else {
                console.log(evt.data);
                $('#chat-display').append('<p>' + evt.data + '</p>');
                let cd = document.getElementById('chat-display');
                cd.scrollTop = cd.scrollHeight;
            }
        };
        ws.onclose = (evt) => console.log("connect closed.");
    </script>
</head>
<body>
<div id="chat-page" style="display: none">
    <div id="up">
        <nav>
            <strong>
                AJ Chat
            </strong>
        </nav>
    </div>
    <div id="chat-display">
        <p>
            <b class="un">admin</b>: aj!
        </p>
    </div>
    <div id="chat-send">
        <label>
            <input id="chat-text">
        </label>
        <button type="button" id="chat-button" onclick="(() => {
            let m = $('#chat-text');
            let mv = m.val();
            if (mv.length !== 0) {
                ws.send(mv);
                m.val('');
            }
        })()">Send</button>
    </div>

</div>
<div class="wrapper">
    <div id="snackbar"><strong id="error-msg">发生致命错误!</strong></div>
    <div id="snackbar-ok"><strong id="ok-msg">ok</strong></div>
    <div class="container">
        <h1>AJ Chat</h1>
        <form class="form">
            <label>
                <input id="username" type="text" placeholder="Username" maxlength="30">
                <input id="password" type="password" placeholder="Password">
            </label>
            <button type="button" id="login-button" onclick="(() => {
                let u = $('#username').val();
                let p = $('#password').val();
                if (u.length !== 0 && p.length !== 0) {
                    ws.send('l ' + window.btoa(window.encodeURIComponent(u)) + ' ' + hex_md5(p));
                }
            })()">Login</button>
            <button type="button" id="register-button" onclick="(() => {
                let u = $('#username').val();
                let p = $('#password').val();
                if (u.length !== 0 && p.length !== 0) {
                    reg = true;
                    ws.send('r ' + window.btoa(window.encodeURIComponent(u)) + ' ' + hex_md5(p));
                }
            })()">Register</button>
        </form>
    </div>
    <ul class="bg-bubbles">
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</div>
</body>
</html>

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注