├── .idea ├── misc.xml ├── vcs.xml └── modules.xml ├── node.iml ├── .github └── FUNDING.yml ├── ssl ├── example.privkey.pem ├── example.cert.pem └── example.fullchain.pem ├── index.js ├── postfix ├── main.cf └── master.cf ├── module ├── md5 │ └── md5.js └── api │ └── api.js └── index.html /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /node.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: javascriptteacher # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: js_tut 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://www.paypal.me/learningcurve1 13 | -------------------------------------------------------------------------------- /ssl/example.privkey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC+lghpfmM9oltK 3 | BW/Y3JFP9FwQoQJnpPaEE0WYsSxgJZZ+su3ugMZH3a0W1xRwMOY/9TtwgXAKSc+4 4 | 7WJjdIvHgbSavUx5hoYBPMT1uqg6vBMi6oT8n/EUvlvoYUUtVbNPV+ZQgNQ1Iz7N 5 | 6JMYYh2bvJu77PsZBhKz3BTEgVBhgE6pUqhjhSaorzXndi2bo/cE7WvqnAEKns6X 6 | lgM13BLUX5vU5/ZQTJ7cav2bw8XhCKDsYMowitc6hlI1zLEcH6XTyzKxPu9cfqgX 7 | TDZbPLgR+G++O8P7eMghJNwqmgX6zSJVFlH0OFxiH3HBWmpNOvQK+thPkl4LH6t2 8 | 5lmkeIH/AgMBAAECggEBAJepXNhWMzMA2BR3byHro9c0ZW72Mau4olNH4sI3e1Cn 9 | mLMKQDzjTOYziWH7ldARmaibxckpt7b4Ncy7Wug5/mGs3cOlkA3E9y5U5YeGGglj 10 | UPcgGOPPg1E2inzJqvsAj8g78pNtcXE3suq4gRWOPnGIDYXmd4raQlfOcthM72Im 11 | EB7O6UZhriYqIshbi53qRQlMSfcIcJjonmIH48QgrWU1PWpX/ggILYX3PErmAIop 12 | rhPPd7oiTuOgDJZ3mZhSTmm5CaFw8OQ8NRtveqCVzMA9SJGYAMeUzL2acSYY1l70 13 | wdT+Jv1PhTRxO9M782jWJvK9AIVYjYFDKRh8Y1w7bAECgYEA7BRqJTTsUJ9Gl/sI 14 | qmaJN/gDuEoXNqOD79MVVV/4IAqQ+5prnIlO6eMCYkwxvAHKM4uGAs9ijHRhw+F8 15 | wuGKpMWtNQNJfEg+ObVTqauqCtaPqFpoCTnVQ9riWDZQnAcyQEogw4jq95KtNcDp 16 | Gm7KufaZULX2eGEaYLQu5qwI6MECgYEAzqrnc6T7JT6oOrc5sjTM+kB3uYBOPyU0 17 | R/9qdpAqJ8YQRayd2JRXfWCWG/zRUxwFzIqcSH2oRHYx1ABVMUNH4mensZoJTwEG 18 | EdNSBAbKBVz5mh4KshRucSNkaVOfyRp3fzs4zlVbmNzYS5vzxeP3v4Oc7c7QdyZi 19 | i9oiPoC/Wr8CgYEA66lxUBTldZGZeatJOjjC75Dvva6QP6W41dWDrUbwvKNvmQnM 20 | NGXI1acbwR5IY2HyA8RakUGOIaEn2s6jqTJWISeHQK04VQ0UuKyuiGfphYoru6YL 21 | xnHp1yOP4PjPPQHeAtk8nZR24Y6Uw10AFLfWPQ7SewQ5tm9QUopray7+ccECgYEA 22 | s5RX5+oc/QEUB2k87jfpQS8RmZP+6em3IzSy2vFsYAFAFHro8c/8sgpihVFKxs/b 23 | zh9Hq8nclBisNY5QeK0A4p+1XKL/obG/B3A7nRoVI1Hl5eBi5NjSGudpEgjDGGky 24 | GtFoDAqpvAtyu0h5K6Rqm/SOQSnrhQ1KpkFWbj9Lh1sCgYAZHSi9u+GzdMF9/FJU 25 | 3ZUk/lOGGE0+NI86/Ezfs167d4HHHQiftGqYbuc4SwycBphyZUlWa1IHxGNhPdVP 26 | mW+YsFbpVQSJlVXx7ENMAVuZiDIR4F252q1i1fMNwDsmQRCN/GE979I2ZzCAYann 27 | mkaIVon4F8pH8iQAp35ByCbDBA== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /ssl/example.cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFYTCCBEmgAwIBAgISAz1WISCxrzfW/0bLHPlCYOMaMA0GCSqGSIb3DQEBCwUA 3 | MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD 4 | ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA0MjUwMTU0MDZaFw0y 5 | MDA3MjQwMTU0MDZaMBcxFTATBgNVBAMTDG5leHRsaXN0Lm9yZzCCASIwDQYJKoZI 6 | hvcNAQEBBQADggEPADCCAQoCggEBAL6WCGl+Yz2iW0oFb9jckU/0XBChAmek9oQT 7 | RZixLGAlln6y7e6AxkfdrRbXFHAw5j/1O3CBcApJz7jtYmN0i8eBtJq9THmGhgE8 8 | xPW6qDq8EyLqhPyf8RS+W+hhRS1Vs09X5lCA1DUjPs3okxhiHZu8m7vs+xkGErPc 9 | FMSBUGGATqlSqGOFJqivNed2LZuj9wTta+qcAQqezpeWAzXcEtRfm9Tn9lBMntxq 10 | /ZvDxeEIoOxgyjCK1zqGUjXMsRwfpdPLMrE+71x+qBdMNls8uBH4b747w/t4yCEk 11 | 3CqaBfrNIlUWUfQ4XGIfccFaak069Ar62E+SXgsfq3bmWaR4gf8CAwEAAaOCAnIw 12 | ggJuMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH 13 | AwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUmO/G33QgxU7wuMBuKc8OoZLEt0kw 14 | HwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl7/Oo7KEwbwYIKwYBBQUHAQEEYzBh 15 | MC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5pbnQteDMubGV0c2VuY3J5cHQub3Jn 16 | MC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDMubGV0c2VuY3J5cHQub3Jn 17 | LzApBgNVHREEIjAgggxuZXh0bGlzdC5vcmeCEHd3dy5uZXh0bGlzdC5vcmcwTAYD 18 | VR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYa 19 | aHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEDBgorBgEEAdZ5AgQCBIH0BIHx 20 | AO8AdgDnEvKwN34aYvuOyQxhhPHqezfLVh0RJlvz4PNL8kFUbgAAAXGvQaI0AAAE 21 | AwBHMEUCIGswaG+fYc+U8UZ9dNQrHpQw2xTvDJKpLc1ey0MqFgQ/AiEAmsosaGsl 22 | sLyw8zGuqffAOCc2rC6Idi/2HUkkPDpCPQIAdQAHt1wb5X1o//Gwxh0jFce65ld8 23 | V5S3au68YToaadOiHAAAAXGvQaJCAAAEAwBGMEQCICQbultYCCEA3UzMTlY25llW 24 | fnqDHSleKFStf7Cpgy/4AiAg9B27a9n06covmr4fLeU81PhOFnvGxy7zYPOckV94 25 | sTANBgkqhkiG9w0BAQsFAAOCAQEAVD6gn+1IR0sqYNrn2QPHp9DU9F5J853GfQKl 26 | Ya+TQCk9cX04rcRSfA+diVk1+7spnjmIg3Pph2r5LXyNynJvSvUYYryQjfi7MU3u 27 | klFhequKPqssAZqZttPpfcsRiNf9wQSMDYkP2tAFNHDfiAGWfQcmTWmHNwKzkysW 28 | TD5oG03znnErtSDO8aCnc2JHaxVCzlq25rw44FbMsPl0VJDNoYsgorkJ0BxcfgN2 29 | NS2ZODCkYb5hA9aDq6gw1/f9XZu59Sx4+kLrahv7la9SZR1CzvNJW3zaUNKjkxb8 30 | voMwT2dw7FFIAmYUwr/toqcdp4cCQ6i1bTLw17P2WCvY8oJhPw== 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let http = require('http'); 2 | let fs = require('fs'); 3 | let path = require('path'); 4 | 5 | /* note, mysql must be installed (npm install mysql) and mysql server running on localhost or elsewhere*/ 6 | let { API, database } = require('./module/api/api.js'); 7 | 8 | database.create(); 9 | 10 | process.env.node_env = "localhost"; 11 | 12 | // replace xx.xx.xx.xxx with your own remote IP address or localhost (127.0.0.1) 13 | const ip = '23.239.21.207'; 14 | const port = process.env.node_env === 'production' ? 80 : 3000; 15 | 16 | http.createServer(function(request, response) { 17 | 18 | console.log('request ', request.url); 19 | 20 | let filename = '.' + request.url; 21 | if (filename == './') 22 | filename = './index.html'; 23 | 24 | let extension = String(path.extname(filename)).toLowerCase(); 25 | let mime = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpg', '.gif': 'image/gif', } 26 | let contentType = mime[extension] || 'application/octet-stream'; 27 | 28 | fs.readFile(filename, function (error, content) { 29 | if (error) { 30 | if (error.code == 'ENOENT') { 31 | if (API.catchAPIrequest( request.url )) 32 | API.exec(request, response); 33 | else 34 | fs.readFile('./404.html', function (error, content) { 35 | response.writeHead(200, { 'Content-Type': contentType }); 36 | response.end(content, 'utf-8'); 37 | }); 38 | } else { 39 | response.writeHead(500) 40 | response.end('Server error: ' + error.code + ' ..\n'); 41 | response.end(); 42 | } 43 | } else { 44 | console.log("API request detecting..."); 45 | response.writeHead(200, { 'Content-Type': contentType }); 46 | response.end(content, 'utf-8'); 47 | } 48 | }); 49 | }).listen(port, ip); 50 | 51 | process.on('exit', function () { database.connection.end(); console.log('process.exit'); }); 52 | process.on('SIGINT', function () { console.log('Ctrl-C...'); database.connection.end(); process.exit(2) }); 53 | process.on('uncaughtException', function(e) { console.log(e.stack); database.connection.end(); process.exit(99); }); 54 | 55 | console.log('Server running at http://' + ip + ':' + port + '/'); -------------------------------------------------------------------------------- /postfix/main.cf: -------------------------------------------------------------------------------- 1 | # Replace everywhere it says example.com 2 | # with your own domain name (without www) 3 | 4 | # See /usr/share/postfix/main.cf.dist for a commented, more complete version 5 | 6 | # Debian specific: Specifying a file name will cause the first 7 | # line of that file to be used as the name. The Debian default 8 | # is /etc/mailname. 9 | #myorigin = /etc/mailname 10 | 11 | smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) 12 | biff = no 13 | 14 | # appending .domain is the MUA's job. 15 | append_dot_mydomain = no 16 | 17 | # Uncomment the next line to generate "delayed mail" warnings 18 | #delay_warning_time = 4h 19 | 20 | readme_directory = no 21 | 22 | # See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on 23 | # fresh installs. 24 | compatibility_level = 2 25 | 26 | tls_random_source = dev:/dev/urandom 27 | 28 | smtp_tls_security_level = may 29 | smtp_tls_note_starttls_offer = yes 30 | smtp_tls_mandatory_protocols=!SSLv2,!SSLv3 31 | smtp_tls_protocols=!SSLv2,!SSLv3 32 | smtp_tls_loglevel = 1 33 | smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache 34 | smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache 35 | 36 | # Enable TLS 37 | #smtpd_tls_security_level = may 38 | smtpd_tls_ask_ccert = yes 39 | #smtpd_tls_session_cache_timeout = 3600s 40 | 41 | # TLS parameters 42 | #smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem 43 | #smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key 44 | smtpd_use_tls=yes 45 | smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache 46 | smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache 47 | 48 | # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for 49 | # information on enabling SSL in the smtp client. 50 | 51 | smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination 52 | myhostname = example.com 53 | alias_maps = hash:/etc/aliases 54 | alias_database = hash:/etc/aliases 55 | myorigin = /etc/mailname 56 | mydestination = $myhostname, example.com, localhost, localhost.localdomain, localhost 57 | relayhost = 58 | mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 59 | mailbox_size_limit = 0 60 | recipient_delimiter = + 61 | inet_interfaces = all 62 | inet_protocols = all 63 | 64 | virtual_alias_domains = example.com 65 | 66 | milter_protocol = 2 67 | milter_default_action = accept 68 | smtpd_milters = inet:localhost:8891 69 | non_smtpd_milters = inet:localhost:8891 70 | -------------------------------------------------------------------------------- /ssl/example.fullchain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFYTCCBEmgAwIBAgISAz1WISCxrzfW/0bLHPlCYOMaMA0GCSqGSIb3DQEBCwUA 3 | MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD 4 | ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA0MjUwMTU0MDZaFw0y 5 | MDA3MjQwMTU0MDZaMBcxFTATBgNVBAMTDG5leHRsaXN0Lm9yZzCCASIwDQYJKoZI 6 | hvcNAQEBBQADggEPADCCAQoCggEBAL6WCGl+Yz2iW0oFb9jckU/0XBChAmek9oQT 7 | RZixLGAlln6y7e6AxkfdrRbXFHAw5j/1O3CBcApJz7jtYmN0i8eBtJq9THmGhgE8 8 | xPW6qDq8EyLqhPyf8RS+W+hhRS1Vs09X5lCA1DUjPs3okxhiHZu8m7vs+xkGErPc 9 | FMSBUGGATqlSqGOFJqivNed2LZuj9wTta+qcAQqezpeWAzXcEtRfm9Tn9lBMntxq 10 | /ZvDxeEIoOxgyjCK1zqGUjXMsRwfpdPLMrE+71x+qBdMNls8uBH4b747w/t4yCEk 11 | 3CqaBfrNIlUWUfQ4XGIfccFaak069Ar62E+SXgsfq3bmWaR4gf8CAwEAAaOCAnIw 12 | ggJuMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH 13 | AwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUmO/G33QgxU7wuMBuKc8OoZLEt0kw 14 | HwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl7/Oo7KEwbwYIKwYBBQUHAQEEYzBh 15 | MC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5pbnQteDMubGV0c2VuY3J5cHQub3Jn 16 | MC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDMubGV0c2VuY3J5cHQub3Jn 17 | LzApBgNVHREEIjAgggxuZXh0bGlzdC5vcmeCEHd3dy5uZXh0bGlzdC5vcmcwTAYD 18 | VR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYa 19 | aHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEDBgorBgEEAdZ5AgQCBIH0BIHx 20 | AO8AdgDnEvKwN34aYvuOyQxhhPHqezfLVh0RJlvz4PNL8kFUbgAAAXGvQaI0AAAE 21 | AwBHMEUCIGswaG+fYc+U8UZ9dNQrHpQw2xTvDJKpLc1ey0MqFgQ/AiEAmsosaGsl 22 | sLyw8zGuqffAOCc2rC6Idi/2HUkkPDpCPQIAdQAHt1wb5X1o//Gwxh0jFce65ld8 23 | V5S3au68YToaadOiHAAAAXGvQaJCAAAEAwBGMEQCICQbultYCCEA3UzMTlY25llW 24 | fnqDHSleKFStf7Cpgy/4AiAg9B27a9n06covmr4fLeU81PhOFnvGxy7zYPOckV94 25 | sTANBgkqhkiG9w0BAQsFAAOCAQEAVD6gn+1IR0sqYNrn2QPHp9DU9F5J853GfQKl 26 | Ya+TQCk9cX04rcRSfA+diVk1+7spnjmIg3Pph2r5LXyNynJvSvUYYryQjfi7MU3u 27 | klFhequKPqssAZqZttPpfcsRiNf9wQSMDYkP2tAFNHDfiAGWfQcmTWmHNwKzkysW 28 | TD5oG03znnErtSDO8aCnc2JHaxVCzlq25rw44FbMsPl0VJDNoYsgorkJ0BxcfgN2 29 | NS2ZODCkYb5hA9aDq6gw1/f9XZu59Sx4+kLrahv7la9SZR1CzvNJW3zaUNKjkxb8 30 | voMwT2dw7FFIAmYUwr/toqcdp4cCQ6i1bTLw17P2WCvY8oJhPw== 31 | -----END CERTIFICATE----- 32 | -----BEGIN CERTIFICATE----- 33 | MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ 34 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 35 | DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow 36 | SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT 37 | GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC 38 | AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF 39 | q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 40 | SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 41 | Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA 42 | a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj 43 | /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T 44 | AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG 45 | CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv 46 | bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k 47 | c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw 48 | VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC 49 | ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz 50 | MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu 51 | Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF 52 | AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo 53 | uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ 54 | wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu 55 | X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG 56 | PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 57 | KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== 58 | -----END CERTIFICATE----- 59 | -------------------------------------------------------------------------------- /module/md5/md5.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for more info. 8 | */ 9 | var hexcase=0;function md5(a){return rstr2hex(rstr_md5(str2rstr_utf8(a)))}function hex_hmac_md5(a,b){return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function md5_vm_test(){return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72"}function rstr_md5(a){return binl2rstr(binl_md5(rstr2binl(a),a.length*8))}function rstr_hmac_md5(c,f){var e=rstr2binl(c);if(e.length>16){e=binl_md5(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_md5(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_md5(d.concat(g),512+128))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binl(b){var a=Array(b.length>>2);for(var c=0;c>5]|=(b.charCodeAt(c/8)&255)<<(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c>5]>>>(c%32))&255)}return a}function binl_md5(p,k){p[k>>5]|=128<<((k)%32);p[(((k+64)>>>9)<<4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<>>(32-b))}; 10 | /* 11 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 12 | * Digest Algorithm, as defined in RFC 1321. 13 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 14 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 15 | * Distributed under the BSD License 16 | * See http://pajhome.org.uk/crypt/md5 for more info. 17 | */ 18 | 19 | module.exports = md5; -------------------------------------------------------------------------------- /postfix/master.cf: -------------------------------------------------------------------------------- 1 | # 2 | # Postfix master process configuration file. For details on the format 3 | # of the file, see the master(5) manual page (command: "man 5 master" or 4 | # on-line: http://www.postfix.org/master.5.html). 5 | # 6 | # Do not forget to execute "postfix reload" after editing this file. 7 | # 8 | # ========================================================================== 9 | # service type private unpriv chroot wakeup maxproc command + args 10 | # (yes) (yes) (no) (never) (100) 11 | # ========================================================================== 12 | smtp inet n - y - - smtpd 13 | #smtp inet n - y - 1 postscreen 14 | #smtpd pass - - y - - smtpd 15 | #dnsblog unix - - y - 0 dnsblog 16 | #tlsproxy unix - - y - 0 tlsproxy 17 | submission inet n - n - - smtpd 18 | # -o syslog_name=postfix/submission 19 | # -o smtpd_tls_security_level=encrypt 20 | -o smtpd_sasl_auth_enable=yes 21 | # -o smtpd_tls_auth_only=yes 22 | # -o smtpd_reject_unlisted_recipient=no 23 | # -o smtpd_client_restrictions=$mua_client_restrictions 24 | -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject 25 | -o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject 26 | -o smtpd_helo_restrictions=permit_mynetworks,permit 27 | -o smtpd_tls_security_level=encrypt 28 | # -o smtpd_helo_restrictions=$mua_helo_restrictions 29 | # -o smtpd_sender_restrictions=$mua_sender_restrictions 30 | # -o smtpd_recipient_restrictions= 31 | # -o smtpd_relay_restrictions=permit_sasl_authenticated,reject 32 | # -o milter_macro_daemon_name=ORIGINATING 33 | #smtps inet n - y - - smtpd 34 | # -o syslog_name=postfix/smtps 35 | # -o smtpd_tls_wrappermode=yes 36 | # -o smtpd_sasl_auth_enable=yes 37 | # -o smtpd_reject_unlisted_recipient=no 38 | # -o smtpd_client_restrictions=$mua_client_restrictions 39 | # -o smtpd_helo_restrictions=$mua_helo_restrictions 40 | # -o smtpd_sender_restrictions=$mua_sender_restrictions 41 | # -o smtpd_recipient_restrictions= 42 | # -o smtpd_relay_restrictions=permit_sasl_authenticated,reject 43 | # -o milter_macro_daemon_name=ORIGINATING 44 | #628 inet n - y - - qmqpd 45 | pickup unix n - y 60 1 pickup 46 | cleanup unix n - y - 0 cleanup 47 | qmgr unix n - n 300 1 qmgr 48 | #qmgr unix n - n 300 1 oqmgr 49 | tlsmgr unix - - y 1000? 1 tlsmgr 50 | rewrite unix - - y - - trivial-rewrite 51 | bounce unix - - y - 0 bounce 52 | defer unix - - y - 0 bounce 53 | trace unix - - y - 0 bounce 54 | verify unix - - y - 1 verify 55 | flush unix n - y 1000? 0 flush 56 | proxymap unix - - n - - proxymap 57 | proxywrite unix - - n - 1 proxymap 58 | smtp unix - - y - - smtp 59 | relay unix - - y - - smtp 60 | -o syslog_name=postfix/$service_name 61 | # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 62 | showq unix n - y - - showq 63 | error unix - - y - - error 64 | retry unix - - y - - error 65 | discard unix - - y - - discard 66 | local unix - n n - - local 67 | virtual unix - n n - - virtual 68 | lmtp unix - - y - - lmtp 69 | anvil unix - - y - 1 anvil 70 | scache unix - - y - 1 scache 71 | # 72 | # ==================================================================== 73 | # Interfaces to non-Postfix software. Be sure to examine the manual 74 | # pages of the non-Postfix software to find out what options it wants. 75 | # 76 | # Many of the following services use the Postfix pipe(8) delivery 77 | # agent. See the pipe(8) man page for information about ${recipient} 78 | # and other message envelope options. 79 | # ==================================================================== 80 | # 81 | # maildrop. See the Postfix MAILDROP_README file for details. 82 | # Also specify in main.cf: maildrop_destination_recipient_limit=1 83 | # 84 | maildrop unix - n n - - pipe 85 | flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} 86 | # 87 | # ==================================================================== 88 | # 89 | # Recent Cyrus versions can use the existing "lmtp" master.cf entry. 90 | # 91 | # Specify in cyrus.conf: 92 | # lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 93 | # 94 | # Specify in main.cf one or more of the following: 95 | # mailbox_transport = lmtp:inet:localhost 96 | # virtual_transport = lmtp:inet:localhost 97 | # 98 | # ==================================================================== 99 | # 100 | # Cyrus 2.1.5 (Amos Gouaux) 101 | # Also specify in main.cf: cyrus_destination_recipient_limit=1 102 | # 103 | #cyrus unix - n n - - pipe 104 | # user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} 105 | # 106 | # ==================================================================== 107 | # Old example of delivery via Cyrus. 108 | # 109 | #old-cyrus unix - n n - - pipe 110 | # flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} 111 | # 112 | # ==================================================================== 113 | # 114 | # See the Postfix UUCP_README file for configuration details. 115 | # 116 | uucp unix - n n - - pipe 117 | flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) 118 | # 119 | # Other external delivery methods. 120 | # 121 | ifmail unix - n n - - pipe 122 | flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) 123 | bsmtp unix - n n - - pipe 124 | flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient 125 | scalemail-backend unix - n n - 2 pipe 126 | flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} 127 | mailman unix - n n - - pipe 128 | flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py 129 | ${nexthop} ${user} 130 | 131 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Node API Endpoint Server 4 | 5 | 137 | 140 | 141 | 142 | 143 |
144 |
145 | API Tests
146 | 147 | 148 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /module/api/api.js: -------------------------------------------------------------------------------- 1 | const ip = require('ip'); 2 | const mysql = require('mysql'); 3 | // Standard MD5 hashing algorithm 4 | const md5 = require('./../md5/md5.js'); 5 | // Standard FIPS 202 SHA-3 implementation 6 | const { SHA3 } = require('sha3'); 7 | // The Keccak hash function is also available 8 | const { Keccak } = require('sha3'); 9 | 10 | // Generate timestamp: if full argument is false/undefined, 11 | // timestamp is divided by 1000 to generate linux-length timestamp 12 | function timestamp(full) { 13 | let date = new Date(); 14 | let timestamp = date.getTime(); 15 | return full ? Math.floor(timestamp) : Math.floor(timestamp / 1000); 16 | } 17 | 18 | // Generate string "1s", "2h", etc between now and "time" argument 19 | function elapsed( time ) { 20 | const $SECONDS = Math.abs(timestamp() - time); 21 | const $iv_table = ["s","min","h","d","mo","y","s","min","h","d","mo","y"]; 22 | const $iv = [$SECONDS, 23 | ($SECONDS-($SECONDS%60))/60, 24 | ($SECONDS-($SECONDS%3600))/3600, 25 | ($SECONDS-($SECONDS%(3600*24)))/(3600*24), 26 | ($SECONDS-($SECONDS%(3600*24*30)))/(3600*24*30), 27 | ($SECONDS-($SECONDS%(3600*24*30*12)))/(3600*24*30*12)]; 28 | for (let $i = 5; $i >= 0; $i--) { 29 | $r = $iv[$i]; 30 | if ($r > 0) { 31 | if (($r > 1 || $r == 0)) 32 | $i += 6; 33 | return $r + "" + $iv_table[$i]; 34 | } 35 | } 36 | } 37 | 38 | // Check if property with value exists on an object 39 | Object.prototype.exists = function(property_name, value) { 40 | for (let i = 0; i < this.length; i++) { 41 | let o = this[i]; 42 | if (o[property_name] != undefined) 43 | if (o[property_name] == value) 44 | return true; 45 | } 46 | return false; 47 | } 48 | 49 | // Check if value exists in array 50 | Array.prototype.exists = function(value) { 51 | for (let i = 0; i < this.length; i++) 52 | if (this[i] == value) 53 | return true; 54 | return false; 55 | } 56 | 57 | class database { 58 | constructor() { } 59 | static create() { 60 | let message = "Creating MySQL connection..."; 61 | this.connection = mysql.createConnection({ 62 | host : 'XX.XX.XX.XXX', // or localhost 63 | user : 'root', 64 | password : 'PassWord123!', 65 | database : 'databasename' 66 | }); 67 | this.connection.connect(); 68 | console.log(message + "Ok."); 69 | } 70 | } 71 | 72 | // Requires payload.email_address = 73 | function action_register_user ( request, payload ) { 74 | return new Promise((resolve, reject) => { 75 | if (!request || !request.headers || !payload) 76 | reject("Error: Wrong request, missing request headers, or missing payload"); 77 | let q = `SELECT email_address FROM user WHERE email_address = '${payload.email_address}' LIMIT 1`; 78 | database.connection.query(q, 79 | (error, results) => { // Check if user already exists in database 80 | if (error) 81 | throw(error); 82 | let result = results[0]; 83 | if (results && results.length != 0 && result.email_address == payload.email_address) 84 | resolve(`{"success": false, "message": "user already exists"}`); 85 | else { 86 | let avatar = JSON.stringify({"head": 1, "eyes": 1}); 87 | // Encrypt payload.password with md5 algorithm 88 | let password_md5 = md5(payload.password); 89 | let fields = "( `username`, `email_address`, `password_md5`, `first_name`, `last_name`, `avatar` )"; 90 | let values = `VALUES( '${payload.username}', '${payload.email_address}', '${password_md5}', 'first', 'last', '${avatar}')`; 91 | database.connection.query("INSERT INTO user " + fields + " " + values, 92 | (error, results) => { // Create new user in database 93 | if (error) 94 | throw(error); 95 | resolve(`{"success": true, "message": "user registered"}`); 96 | }); 97 | } 98 | }); 99 | }).catch((error) => { console.log(error) }); 100 | } 101 | 102 | // Requires payload.id = 103 | function action_get_user ( request, payload ) { 104 | return new Promise((resolve, reject) => { 105 | if (!request || !request.headers || !payload) 106 | reject("Error: Wrong request, missing request headers, or missing payload"); 107 | database.connection.query("SELECT * FROM user WHERE id = '" + payload.id + "' LIMIT 1", 108 | (error, results) => { // Check if user already exists in database 109 | if (error) throw(error); 110 | let result = results[0]; 111 | if (results && results.length != 0 && result.id == payload.id) { 112 | result.found = true; 113 | resolve(`{"found": true, "user": ${JSON.stringify(result)}, "message": "user found"}`); 114 | } else 115 | resolve(`{"found": false, "user": null, "message": "user with this id doesn't exist"}`); 116 | }); 117 | }).catch(error => console.log(error)); 118 | } 119 | 120 | function action_get_user_promiseless ( request, payload ) { 121 | return new Promise((resolve, reject) => { 122 | if (!request || !request.headers || !payload) 123 | reject("Error: Wrong request, missing request headers, or missing payload"); 124 | database.connection.query("SELECT * FROM user WHERE id = '" + payload.id + "' LIMIT 1", 125 | (error, results) => { // Check if user already exists in database 126 | if (error) throw(error); 127 | let result = results[0]; 128 | if (results && results.length != 0 && result.id == payload.id) { 129 | resolve(`{"found": true, "user": ${JSON.stringify(result)}, "message": "user found"}`); 130 | } else 131 | resolve(`{"found": false, "user": null, "message": "user with this id doesn't exist"}`); 132 | }); 133 | }).catch(error => console.log(error)); 134 | } 135 | 136 | function action_delete_user ( request, payload ) { 137 | return new Promise((resolve, reject) => { 138 | // Header or payload are missing 139 | if (!request || !request.headers || !payload) 140 | reject("Error: Wrong request, missing request headers, or missing payload"); 141 | // Payload must specify user id 142 | if (!payload.id) 143 | reject("User id not specified!"); 144 | let query = "DELETE from `user` WHERE `id` = " + payload.id; 145 | database.connection.query(query, (error, results) => { 146 | if (error) 147 | throw(error); 148 | let result = results[0]; 149 | console.log("results[0] = ", results[0]); 150 | console.log("result = ", result); 151 | resolve(`{"success": true, "message": "user updated!"}`); 152 | }); 153 | }).catch(error => console.log(error)); 154 | } 155 | 156 | function action_update_user ( request, payload ) { 157 | return new Promise((resolve, reject) => { 158 | // Header or payload are missing 159 | if (!request || !request.headers || !payload) 160 | reject("Error: Wrong request, missing request headers, or missing payload"); 161 | // Payload must specify user id 162 | if (!payload.id) 163 | reject("User id not specified!"); 164 | // Columns allowed to be changed: 165 | let allowed = ["id", "email_address", "password_md5"]; 166 | // Exclude not-allowed fields from payload 167 | Object.entries(payload).map((value, index, obj) => { 168 | let name = value[0]; 169 | if (!allowed.exists(name)) delete payload[name]; 170 | }); 171 | // Start MySQL query 172 | let query = "UPDATE user SET "; 173 | // Build the rest of MySQL query from payload 174 | Object.entries(payload).map((item, index, object) => { 175 | let name = item[0]; 176 | let value = payload[name]; 177 | index != 0 ? query += ", " : null; 178 | query += "`" + name + "` = '" + value + "'"; 179 | }); 180 | // End query 181 | query += " WHERE `id` = '" + payload.id + "'"; 182 | // Execute MySQL query we just created 183 | database.connection.query(query, (error, results) => { 184 | if (error) 185 | throw(error); 186 | let result = results[0]; 187 | console.log("results[0] = ", results[0]); 188 | console.log("result = ", result); 189 | resolve(`{"success": true, "message": "user updated!"}`); 190 | }); 191 | 192 | }).catch(error => null ); 193 | } 194 | 195 | function action_login ( request, payload ) { 196 | return new Promise((resolve, reject) => { 197 | // First, get the user from database by payload.id 198 | let query = `SELECT * FROM \`user\` WHERE \`username\` = '${payload.username}'`; 199 | console.log(query); 200 | database.connection.query(query, 201 | (error, results) => { // Check if user already exists in database 202 | if (error) 203 | throw(error); 204 | let result = results[0]; 205 | /* console.log("result = ", result); 206 | console.log("payload.username = ", payload.username); 207 | console.log("payload.password = ", payload.password); 208 | console.log("password 1 = ", md5(payload.password)); 209 | console.log("password 2 = ", result.password_md5); */ 210 | if (results && results.length != 0 && result.username == payload.username) { 211 | // result.found = true; 212 | // Check if submitted password is correct 213 | if (md5(payload.password) == result.password_md5) { 214 | delete result.email_address; // don't send email to front-end 215 | delete result.password_md5; // don't send md5 password to front-end 216 | resolve(`{"success": true, "user": ${JSON.stringify(result)}, "message": "user successfully logged in!"}`); 217 | } else 218 | resolve(`{"success": false, "user": null, "message": "incorrect username or password"}`); 219 | } 220 | // User not found 221 | resolve(`{"success": false, "user": null, "message": "user with this username(${payload.username}) doesn't exist"}`); 222 | }); 223 | }).catch(error => console.log(error)); 224 | } 225 | 226 | function action_logout ( request, payload ) { 227 | return new Promise((resolve, reject) => { 228 | /* implement */ 229 | }).catch(error => console.log(error));; 230 | } 231 | 232 | function action_create_session( request, payload ) { 233 | // Create unique authentication token 234 | function create_auth_token() { 235 | let token = md5( timestamp( true ) + ""); 236 | return token; 237 | } 238 | return new Promise((resolve, reject) => { 239 | if (!request || !request.headers || !payload) 240 | reject("Error: Wrong request, missing request headers, or missing payload"); 241 | database.connection.query("SELECT * FROM session WHERE user_id = '" + payload.id + "' LIMIT 1", 242 | (error, results) => { // Check if session already exists 243 | if (error) throw(error); 244 | let result = results[0]; 245 | if (results && results.length != 0 && result.user_id == payload.id) { 246 | result.found = true; 247 | resolve(`{"found": true, 248 | "token": token, 249 | "session": ${JSON.stringify(result)}, 250 | "message": "session already exists"}`); 251 | } else { // This session doesn't exist, create it 252 | // Create auth token 253 | let token = create_auth_token(); 254 | database.connection.query("INSERT INTO session ( `user_id`, `timestamp`, `token`) VALUES( '" + payload.id + "', '" + timestamp() + "', '" + token + "')", 255 | (error, results) => { 256 | if (error) throw(error); 257 | resolve(`{"found" : false, 258 | "token" : token, 259 | "user_id": ${payload.user_id}, 260 | "message": "session was created"}`); 261 | }); 262 | } 263 | }); 264 | }).catch(error => { console.log(error) }); 265 | } 266 | 267 | function action_get_session( request, payload ) { 268 | return new Promise((resolve, reject) => { 269 | if (!request || !request.headers || !payload) 270 | reject("Error: Wrong request, missing request headers, or missing payload"); 271 | database.connection.query("SELECT * FROM session WHERE user_id = '" + payload.id + "' LIMIT 1", 272 | (error, results) => { // Return session 273 | if (error) 274 | throw(error); 275 | let result = results[0]; 276 | if (results && results.length != 0 && result.user_id == payload.id) { 277 | result.found = true; 278 | resolve(`{"found": true, 279 | "session": ${JSON.stringify(result)}, 280 | "message": "session found"}`); 281 | } else 282 | resolve(`{"found": false, "session": null, "message": "session found"}`); 283 | }); 284 | }).catch((error) => { console.log(error) }); 285 | } 286 | 287 | function action_authenticate_user( request, payload ) { 288 | return new Promise((resolve, reject) => { 289 | if (!request || !request.headers || !payload) 290 | reject("Error: Wrong request, missing request headers, or missing payload"); 291 | database.connection.query("SELECT * FROM session WHERE token = '" + payload.token + "' LIMIT 1", 292 | (error, results) => { // Return session 293 | if (error) 294 | throw(error); 295 | if (results.length == 0) { 296 | console.log("API.authenticate, results.length == 0 (session with token not found)"); 297 | reject(`{"success": false, "message": "token not found in session"}`); 298 | } else { 299 | //console.log( results ); 300 | //console.log( results[0] ); 301 | let token = JSON.stringify({ token: results[0].token, type: "admin" }); 302 | resolve(`{"success": true, "message": "user (id=${results[0].user_id}) was successfully authenticated", "token" : ${token}}`); 303 | } 304 | }); 305 | }).catch((error) => { console.log(error) }); 306 | } 307 | 308 | // Check if API.parts match a URL pattern, example: "api/user/get" 309 | function identify(a, b) { 310 | return API.parts[0] == "api" && API.parts[1] == a && API.parts[2] == b; 311 | } 312 | 313 | // General use respond function -- send json object back to the browser in response to a request 314 | function respond( response, content ) { 315 | console.log("responding = ", [ content ]); 316 | const jsontype = "{ 'Content-Type': 'application/json' }"; 317 | response.writeHead(200, jsontype); 318 | response.end(content, 'utf-8'); 319 | } 320 | 321 | // Convert buffer to JSON object 322 | function json( chunks ) { 323 | return JSON.parse( Buffer.concat( chunks ).toString() ); 324 | } 325 | 326 | class Action { } 327 | 328 | Action.register_user = action_register_user; 329 | Action.login = action_login; 330 | Action.logout = action_logout; 331 | Action.get_user = action_get_user; 332 | Action.delete_user = action_delete_user; 333 | Action.update_user = action_update_user; 334 | Action.authenticate_user = action_authenticate_user; 335 | Action.create_session = action_create_session; 336 | Action.get_session = action_get_session; 337 | 338 | const resp = response => content => respond(response, content); 339 | 340 | class API { 341 | 342 | constructor() { } 343 | 344 | static exec( request, response ) { 345 | 346 | console.log("API.exec(), parts = ", API.parts); 347 | 348 | if (request.method == 'POST') { 349 | 350 | request.url[0] == "/" ? request.url = request.url.substring(1, request.url.length) : null; 351 | request.parts = request.url.split("/"); 352 | request.chunks = []; 353 | 354 | // Start reading POST data chunks 355 | request.on('data', segment => { 356 | if (segment.length > 1e6) // 413 = "Request Entity Too Large" 357 | response.writeHead(413, {'Content-Type': 'text/plain'}).end(); 358 | else 359 | request.chunks.push(segment); 360 | }); 361 | 362 | // Finish reading POST data chunks 363 | request.on('end', () => { // POST data fully received 364 | 365 | API.parts = request.parts; 366 | 367 | if (identify("user", "register")) // Register (create) user 368 | Action.register_user( request, json( request.chunks ) ) 369 | .then( content => respond(response, content) ); 370 | 371 | if (identify("user", "login")) // Log in 372 | Action.login( request, json( request.chunks ) ) 373 | .then( content => respond(response, content) ); 374 | 375 | if (identify("user", "logout")) // Log out 376 | Action.logout( request, json( request.chunks ) ) 377 | .then( content => respond(response, content) ); 378 | 379 | if (identify("user", "delete")) // Delete user 380 | Action.delete_user( request, json( request.chunks ) ) 381 | .then( content => respond(response, content) ); 382 | 383 | if (identify("user", "get")) // Get user data 384 | Action.get_user( request, json( request.chunks ) ) 385 | .then( content => respond(response, content) ); 386 | 387 | if (identify("user", "update")) // Update user 388 | Action.update_user( request, json( request.chunks ) ) 389 | .then( content => respond(response, content) ); 390 | 391 | if (identify("session", "create")) // Create session 392 | Action.create_session( request, json( request.chunks ) ) 393 | .then( content => respond(response, content) ); 394 | 395 | if (identify("user", "authenticate")) // Authenticate user 396 | Action.authenticate_user( request, json( request.chunks ) ) 397 | .then( content => respond(response, content) ); 398 | }); 399 | } 400 | } 401 | static catchAPIrequest(request) { 402 | request[0] == "/" ? request = request.substring(1, request.length) : null; 403 | if (request.constructor === String) 404 | if (request.split("/")[0] == "api") { 405 | API.parts = request.split("/"); 406 | return true; 407 | } 408 | return false; 409 | } 410 | } 411 | 412 | API.parts = null; 413 | 414 | module.exports = { API, database }; --------------------------------------------------------------------------------