diff --git a/site/.env.example b/site/.env.example new file mode 100644 index 0000000000..c59f6f7272 --- /dev/null +++ b/site/.env.example @@ -0,0 +1,12 @@ +NODE_ENV= + +PORT= +BASEURL= +DATABASE_URL= +GITHUB_CLIENT_ID= +GITHUB_CLIENT_SECRET= +MAPBOX_ACCESS_TOKEN= + +JWT_EXP=30d +JWT_ALG=HS512 +JWT_KEY= diff --git a/site/migrations/000-create-users.js b/site/migrations/000-create-users.js new file mode 100644 index 0000000000..76dde745a2 --- /dev/null +++ b/site/migrations/000-create-users.js @@ -0,0 +1,25 @@ +exports.up = DB => { + DB.sql(` + create table if not exists users ( + id serial primary key, + uid character varying(255) not null unique, + name character varying(255), + username character varying(255) not null, + avatar text, + github_token character varying(255), + created_at timestamp with time zone NOT NULL DEFAULT now(), + updated_at timestamp with time zone + ); + + create unique index if not exists users_pkey ON users(id int4_ops); + create unique index if not exists users_uid_key ON users(uid text_ops); + `); +}; + +exports.down = DB => { + DB.sql(` + drop table if exists users cascade; + drop index if exists users_uid_key; + drop index if exists users_pkey; + `); +}; diff --git a/site/migrations/001-create-gists.js b/site/migrations/001-create-gists.js new file mode 100644 index 0000000000..22293f5737 --- /dev/null +++ b/site/migrations/001-create-gists.js @@ -0,0 +1,24 @@ +exports.up = DB => { + DB.sql(` + create table if not exists gists ( + id serial primary key, + uid uuid NOT NULL DEFAULT gen_random_uuid(), + user_id integer REFERENCES users(id) not null, + name character varying(255) not null, + files json not null, + created_at timestamp with time zone NOT NULL DEFAULT now(), + updated_at timestamp with time zone + ); + + create unique index if not exists gists_pkey ON gists(id int4_ops); + create index if not exists gists_user_id_key ON gists(user_id int4_ops); + `); +}; + +exports.down = DB => { + DB.sql(` + drop table if exists gists cascade; + drop index if exists gists_user_id_key; + drop index if exists gists_pkey; + `); +}; diff --git a/site/package-lock.json b/site/package-lock.json index a153716298..7ae4494a92 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1360,6 +1360,11 @@ } } }, + "@polka/redirect": { + "version": "1.0.0-next.0", + "resolved": "https://registry.npmjs.org/@polka/redirect/-/redirect-1.0.0-next.0.tgz", + "integrity": "sha512-ym6ooqMr09+cV+y52p5kszJ0jYcX+nJfm8POrQb7QYowvpPPuneZ71EclHrQSB7a50lcytgR/xtL6AUFdvyEkg==" + }, "@polka/send": { "version": "1.0.0-next.2", "resolved": "https://registry.npmjs.org/@polka/send/-/send-1.0.0-next.2.tgz", @@ -1412,6 +1417,25 @@ "integrity": "sha512-szA3x/3miL90ZJxUCzx9haNbK5/zmPieGraZEe4WI+3srN0eGLiT22NXeMHmyhNEopn+IrxqMc7wdVwvPl8meg==", "dev": true }, + "@types/pg": { + "version": "7.4.14", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-7.4.14.tgz", + "integrity": "sha512-2e4XapP9V/X42IGByC5IHzCzHqLLCNJid8iZBbkk6lkaDMvli8Rk62YE9wjGcLD5Qr5Zaw1ShkQyXy91PI8C0Q==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/pg-types": "*" + } + }, + "@types/pg-types": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@types/pg-types/-/pg-types-1.11.4.tgz", + "integrity": "sha512-WdIiQmE347LGc1Vq3Ki8sk3iyCuLgnccqVzgxek6gEHp2H0p3MQ3jniIHt+bRODXKju4kNQ+mp53lmP5+/9moQ==", + "dev": true, + "requires": { + "moment": ">=2.14.0" + } + }, "@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", @@ -1533,15 +1557,11 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "bagpipe": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/bagpipe/-/bagpipe-0.3.5.tgz", - "integrity": "sha1-40HRZPyyTN8E6n4Ft2XsEMiupqE=" - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", @@ -1604,11 +1624,6 @@ "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", "dev": true }, - "base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" - }, "binary-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", @@ -1625,6 +1640,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1692,12 +1708,22 @@ "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", @@ -1883,7 +1909,8 @@ "codemirror": { "version": "5.46.0", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.46.0.tgz", - "integrity": "sha512-3QpMge0vg4QEhHW3hBAtCipJEWjTJrqLLXdIaWptJOblf1vHFeXLNtFhPai/uX2lnFCehWNk4yOdaMR853Z02w==" + "integrity": "sha512-3QpMge0vg4QEhHW3hBAtCipJEWjTJrqLLXdIaWptJOblf1vHFeXLNtFhPai/uX2lnFCehWNk4yOdaMR853Z02w==", + "dev": true }, "collection-visit": { "version": "1.0.0", @@ -1925,7 +1952,30 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "config": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/config/-/config-3.1.0.tgz", + "integrity": "sha512-t6oDeNQbsIWa+D/KF4959TANzjSHLv1BA/hvL8tHEA3OUSWgBXELKaONSI6nr9oanbKs0DXonjOWLcrtZ3yTAA==", + "dev": true, + "optional": true, + "requires": { + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.0" + } + } + } }, "convert-source-map": { "version": "1.6.0", @@ -1936,16 +1986,6 @@ "safe-buffer": "~5.1.1" } }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -2007,6 +2047,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -2092,11 +2133,6 @@ "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", "optional": true }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, "devalue": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devalue/-/devalue-1.1.0.tgz", @@ -2125,6 +2161,14 @@ "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg==", "dev": true }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "electron-to-chromium": { "version": "1.3.129", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.129.tgz", @@ -2272,21 +2316,6 @@ } } }, - "express-session": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.1.tgz", - "integrity": "sha512-pWvUL8Tl5jUy1MLH7DhgUlpoKeVPUTe+y6WQD9YhcN0C5qAhsh4a8feVjiUXo3TFhIy191YGZ4tewW9edbl2xQ==", - "requires": { - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.0.2", - "parseurl": "~1.3.2", - "safe-buffer": "5.1.2", - "uid-safe": "~2.1.5" - } - }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -2452,16 +2481,6 @@ "map-cache": "^0.2.2" } }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, "fs-minipass": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", @@ -2474,7 +2493,8 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "2.0.6", @@ -2514,6 +2534,7 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2565,7 +2586,8 @@ "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true }, "growl": { "version": "1.10.5", @@ -2673,21 +2695,22 @@ "integrity": "sha512-z6YOZ8ZEnejkcCWlGZzYXNa6i+ZaTfiTg3WhlV/YvnNya3W/RbX1bMVUMTuCrg/DrtTCQxaFCkXCz4FtLpcebg==", "dev": true }, + "httpie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/httpie/-/httpie-1.1.1.tgz", + "integrity": "sha512-KYgUXOhxVPo5mYuFPqnKW14fP5goMGkLc9CRz0WD6b1TCED9nl9wzj4jqr+8LY+AhPJQ/LdCQLRfF2JrBEja5Q==" + }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -2696,12 +2719,14 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "interpret": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true }, "invariant": { "version": "2.2.4", @@ -3017,20 +3042,55 @@ "minimist": "^1.2.0" } }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -3104,6 +3164,41 @@ "integrity": "sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -3237,6 +3332,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3361,6 +3457,12 @@ } } }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "dev": true + }, "mri": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", @@ -3370,7 +3472,8 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -3419,7 +3522,22 @@ "node-fetch": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz", - "integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw==" + "integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw==", + "dev": true + }, + "node-pg-migrate": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/node-pg-migrate/-/node-pg-migrate-3.19.0.tgz", + "integrity": "sha512-IIiiP6oHR9JDOqlIpaRFTnIedPIMXsYiMOkCPCSCGA2e+ZuDn/VS07CbDwVwKA+sBfwR0g5KIBx7QZGAS6sesQ==", + "dev": true, + "requires": { + "@types/pg": "^7.4.0", + "config": ">=1.0.0", + "dotenv": ">=1.0.0", + "lodash": "~4.17.0", + "mkdirp": "~0.5.0", + "yargs": "~13.2.0" + } }, "node-releases": { "version": "1.1.17", @@ -3480,16 +3598,6 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "oauth": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", - "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -3573,15 +3681,11 @@ "integrity": "sha1-3LcCTazVDFK00wPwSALJHAV8dl8=", "dev": true }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -3639,6 +3743,11 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "pako": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", @@ -3696,51 +3805,12 @@ "json-parse-better-errors": "^1.0.1" } }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "dev": true }, - "passport": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", - "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", - "requires": { - "passport-strategy": "1.x.x", - "pause": "0.0.1" - } - }, - "passport-github": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/passport-github/-/passport-github-1.1.0.tgz", - "integrity": "sha1-jOHj/NYa11eOsd9ZWDnkrqEjVdQ=", - "requires": { - "passport-oauth2": "1.x.x" - } - }, - "passport-oauth2": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.5.0.tgz", - "integrity": "sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==", - "requires": { - "base64url": "3.x.x", - "oauth": "0.9.x", - "passport-strategy": "1.x.x", - "uid2": "0.0.x", - "utils-merge": "1.x.x" - } - }, - "passport-strategy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -3750,7 +3820,8 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "2.0.1", @@ -3761,7 +3832,8 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true }, "path-type": { "version": "3.0.0", @@ -3772,10 +3844,61 @@ "pify": "^3.0.0" } }, - "pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + "pg": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.10.0.tgz", + "integrity": "sha512-aE6FZomsyn3OeGv1oM50v7Xu5zR75c15LXdOCwA9GGrfjXsQjzwYpbcTS6OwEMhYfZQS6m/FVU/ilPLiPzJDCw==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "0.1.3", + "pg-pool": "^2.0.4", + "pg-types": "~2.0.0", + "pgpass": "1.x", + "semver": "4.3.2" + }, + "dependencies": { + "semver": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" + } + } + }, + "pg-connection-string": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", + "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g==" + }, + "pg-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.0.1.tgz", + "integrity": "sha512-b7y6QM1VF5nOeX9ukMQ0h8a9z89mojrBHXfJeSug4mhL0YpxNBm83ot2TROyoAmX/ZOX3UbwVO4EbH7i1ZZNiw==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", + "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", + "requires": { + "split": "^1.0.0" + } }, "phin": { "version": "2.9.3", @@ -3831,6 +3954,29 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz", + "integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prismjs": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.16.0.tgz", @@ -3867,11 +4013,6 @@ "once": "^1.3.1" } }, - "random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -3911,6 +4052,7 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, "requires": { "resolve": "^1.1.6" } @@ -4043,6 +4185,7 @@ "version": "1.10.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz", "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==", + "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -4059,11 +4202,6 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, - "retry": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", - "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" - }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -4239,8 +4377,7 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "serialize-javascript": { "version": "1.7.0", @@ -4248,18 +4385,6 @@ "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", "dev": true }, - "session-file-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/session-file-store/-/session-file-store-1.2.0.tgz", - "integrity": "sha512-DkYLYFkkK6u9xyraVHemulhlUuuufLukf7SQxOZSx8SPwkswcaIrls882PaQZ72zRKsyhUVNxOUl9w0lQubUFw==", - "requires": { - "bagpipe": "^0.3.5", - "fs-extra": "^4.0.0", - "object-assign": "^4.1.1", - "retry": "^0.10.0", - "write-file-atomic": "1.3.1" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -4320,6 +4445,7 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, "requires": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -4348,11 +4474,6 @@ } } }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -4541,6 +4662,14 @@ "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", "dev": true }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -4700,6 +4829,11 @@ } } }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "timm": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/timm/-/timm-1.6.1.tgz", @@ -4804,19 +4938,6 @@ } } }, - "uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "requires": { - "random-bytes": "~1.0.0" - } - }, - "uid2": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", - "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" - }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -4880,11 +5001,6 @@ } } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -4958,11 +5074,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -5047,17 +5158,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.1.tgz", - "integrity": "sha1-fUW6MjFjKN0ex9kPYOvA2EW7dZo=", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "xhr": { "version": "2.5.0", @@ -5096,8 +5198,7 @@ "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "y18n": { "version": "4.0.0", @@ -5222,11 +5323,6 @@ } } } - }, - "yootils": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/yootils/-/yootils-0.0.15.tgz", - "integrity": "sha512-GvGLuJ7XHJPGEUQ52vh8fh+vPjfikuGcu7yBswfrsNsHqnAoytOVuSb69eM0j8wQIjMz0U3kY3YsfwMhJgfG9w==" } } } diff --git a/site/package.json b/site/package.json index 5a93669e0d..ac9a3dc6aa 100644 --- a/site/package.json +++ b/site/package.json @@ -4,7 +4,9 @@ "description": "Docs and examples for Svelte", "scripts": { "dev": "sapper dev", + "migrate": "node-pg-migrate -r dotenv/config", "sapper": "sapper build --legacy", + "update_shimport": "cp node_modules/shimport/index.js __sapper__/build/client/shimport@0.0.14.js", "update": "node scripts/update_template.js && node scripts/get-contributors.js", "start": "node __sapper__/build", "cy:run": "cypress run", @@ -13,22 +15,18 @@ "testsrc": "mocha -r esm test/**" }, "dependencies": { + "@polka/redirect": "^1.0.0-next.0", "@polka/send": "^1.0.0-next.2", - "codemirror": "^5.46.0", "devalue": "^1.1.0", "do-not-zip": "^1.0.0", - "express-session": "^1.16.1", "golden-fleece": "^1.0.9", - "marked": "^0.6.2", - "node-fetch": "^2.5.0", - "passport": "^0.4.0", - "passport-github": "^1.1.0", + "httpie": "^1.1.1", + "jsonwebtoken": "^8.5.1", + "marked": "^0.6.1", + "pg": "^7.10.0", "polka": "^1.0.0-next.2", - "prismjs": "^1.16.0", - "session-file-store": "^1.2.0", - "shelljs": "^0.8.3", - "sirv": "^0.4.0", - "yootils": "0.0.15" + "prismjs": "^1.15.0", + "sirv": "^0.4.0" }, "devDependencies": { "@babel/core": "^7.4.4", @@ -44,8 +42,10 @@ "dotenv": "^8.0.0", "eslint-plugin-svelte3": "^1.0.0", "esm": "^3.2.22", - "jimp": "^0.6.4", - "mocha": "^6.1.4", + "jimp": "^0.6.0", + "mocha": "^6.1.3", + "node-fetch": "^2.3.0", + "node-pg-migrate": "^3.18.1", "npm-run-all": "^4.1.5", "rollup": "^1.11.2", "rollup-plugin-babel": "^4.3.2", @@ -56,7 +56,8 @@ "rollup-plugin-svelte": "^5.0.3", "rollup-plugin-terser": "^4.0.4", "sapper": "^0.26.0", - "svelte": "^3.2.0" + "shelljs": "^0.8.3", + "svelte": "^3.0.0" }, "engines": { "node": ">=10.0.0" diff --git a/site/rollup.config.js b/site/rollup.config.js index d39db86c0c..029cf65bcf 100644 --- a/site/rollup.config.js +++ b/site/rollup.config.js @@ -74,9 +74,13 @@ export default { commonjs(), json() ], - external: Object.keys(pkg.dependencies).concat( - require('module').builtinModules || Object.keys(process.binding('natives')) - ), + external: [ + 'yootils', + 'codemirror', + ...Object.keys(pkg.dependencies || {}).concat( + require('module').builtinModules || Object.keys(process.binding('natives')) + ) + ], // temporary, pending Rollup 1.0 experimentalCodeSplitting: true @@ -95,4 +99,4 @@ export default { !dev && terser() ] } -}; \ No newline at end of file +}; diff --git a/site/src/backend/auth.js b/site/src/backend/auth.js new file mode 100644 index 0000000000..7792f4ee37 --- /dev/null +++ b/site/src/backend/auth.js @@ -0,0 +1,150 @@ +import polka from 'polka'; +import devalue from 'devalue'; +import send from '@polka/send'; +import { get, post } from 'httpie'; +import { parse, stringify } from 'querystring'; +import { decode, sign, verify } from './token'; +import { find, query } from '../utils/db'; + +const { + BASEURL, + GITHUB_CLIENT_ID, + GITHUB_CLIENT_SECRET, +} = process.env; + +const OAuth = 'https://github.com/login/oauth'; + +function exit(res, code, msg='') { + const error = msg.charAt(0).toUpperCase() + msg.substring(1); + send(res, code, { error }); +} + +function onError(err, req, res) { + const error = err.message || err; + const code = err.code || err.status || 500; + res.headersSent || send(res, code, { error }); +} + +/** + * Middleware to determine User validity + */ +export async function isUser(req, res) { + const abort = exit.bind(null, res, 401); + + const auth = req.headers.authorization; + if (!auth) return abort('Missing Authorization header'); + + const [scheme, token] = auth.split(' '); + if (scheme !== 'Bearer' || !token) return abort('Invalid Authorization format'); + + let data; + const decoded = decode(token, { complete:true }); + if (!decoded || !decoded.header) return abort('Invalid token'); + + try { + data = await verify(token); + } catch (err) { + return abort(err.message); + } + + const { uid, username } = data; + if (!uid || !username) return abort('Invalid token payload'); + + try { + const row = await find(`select * from users where uid = $1 and username = $2 limit 1`, [uid, username]); + return row || abort('Invalid token'); + } catch (err) { + console.error('Auth.isUser', err); + return send(res, 500, 'Unknown error occurred'); + } +} + +export function toUser(obj={}) { + const { uid, username, name, avatar } = obj; + const token = sign({ uid, username }); + return { uid, username, name, avatar, token }; +} + +export function API() { + const app = polka({ onError }); + + if (GITHUB_CLIENT_ID) { + app.get('/auth/login', (req, res) => { + try { + const Location = `${OAuth}/authorize?` + stringify({ + scope: 'read:user', + client_id: GITHUB_CLIENT_ID, + redirect_uri: `${BASEURL}/auth/callback`, + }); + + send(res, 302, Location, { Location }); + } catch (err) { + console.error('GET /auth/login', err); + send(res, 500); + } + }); + + app.get('/auth/callback', async (req, res) => { + try { + // Trade "code" for "access_token" + const r1 = await post(`${OAuth}/access_token?` + stringify({ + code: req.query.code, + client_id: GITHUB_CLIENT_ID, + client_secret: GITHUB_CLIENT_SECRET, + })); + + // Now fetch User details + const { access_token } = parse(r1.data); + const r2 = await get('https://api.github.com/user', { + headers: { + 'User-Agent': 'svelte.dev', + Authorization: `token ${access_token}` + } + }); + + const { id, name, avatar_url, login } = r2.data; + + // Upsert `users` table + const [user] = await query(` + insert into users(uid, name, username, avatar, github_token) + values ($1, $2, $3, $4, $5) on conflict (uid) do update + set (name, username, avatar, github_token, updated_at) = ($2, $3, $4, $5, now()) + returning * + `, [id, name, login, avatar_url, access_token]); + + send(res, 200, ` + + `, { + 'Content-Type': 'text/html; charset=utf-8' + }); + } catch (err) { + console.error('GET /auth/callback', err); + send(res, 500, err.data, { + 'Content-Type': err.headers['content-type'], + 'Content-Length': err.headers['content-length'] + }); + } + }); + } else { + // Print "Misconfigured" error + app.get('/auth/login', (req, res) => { + send(res, 500, ` +
+In order to use GitHub authentication, you will need to register an OAuth application and create a local .env file:
+GITHUB_CLIENT_ID=[YOUR_APP_ID]\nGITHUB_CLIENT_SECRET=[YOUR_APP_SECRET]\nBASEURL=http://localhost:3000+
The BASEURL
variable should match the callback URL specified for your app.
See also here
+ + `, { + 'Content-Type': 'text/html; charset=utf-8' + }); + }); + } + + return app; +} diff --git a/site/src/backend/token.js b/site/src/backend/token.js new file mode 100644 index 0000000000..9adf7d24f4 --- /dev/null +++ b/site/src/backend/token.js @@ -0,0 +1,22 @@ +import * as jwt from 'jsonwebtoken'; + +const { JWT_KEY, JWT_ALG, JWT_EXP } = process.env; + +const CONFIG = { + expiresIn: JWT_EXP, + issuer: 'https://svelte.dev', + audience: 'https://svelte.dev', + algorithm: JWT_ALG, +}; + +export const decode = jwt.decode; + +export function sign(obj, opts, cb) { + opts = Object.assign({}, opts, CONFIG); + return jwt.sign(obj, JWT_KEY, opts, cb); +} + +export function verify(str, opts, cb) { + opts = Object.assign({}, opts, CONFIG); + return jwt.verify(str, JWT_KEY, opts, cb); +} diff --git a/site/src/components/Repl/ReplWidget.svelte b/site/src/components/Repl/ReplWidget.svelte index e785c697f8..fbdd3622a7 100644 --- a/site/src/components/Repl/ReplWidget.svelte +++ b/site/src/components/Repl/ReplWidget.svelte @@ -28,7 +28,7 @@ } if (gist) { - fetch(`gist/${gist}`).then(r => r.json()).then(data => { + fetch(`repl/${gist}.json`).then(r => r.json()).then(data => { const { id, description, files } = data; name = description; diff --git a/site/src/routes/auth/me.json.js b/site/src/routes/auth/me.json.js index 44aa7c9a6f..f77eaf5b94 100644 --- a/site/src/routes/auth/me.json.js +++ b/site/src/routes/auth/me.json.js @@ -1,10 +1,8 @@ import send from '@polka/send'; +import { isUser, toUser } from '../../backend/auth'; -export function get(req, res) { - if (!req.session || !req.session.passport || !req.session.passport.user) { - return send(res, 200, 'null'); - } - - const { id, username, displayName, photo } = req.session.passport.user; - send(res, 200, { id, username, displayName, photo }); +export async function get(req, res) { + const user = await isUser(req, res); + res.setHeader('Cache-Control', 'private, no-cache, no-store'); + return send(res, 200, user ? toUser(user) : null); } diff --git a/site/src/routes/examples/[slug].json.js b/site/src/routes/examples/[slug].json.js index 2cb0958982..705a4e7e89 100644 --- a/site/src/routes/examples/[slug].json.js +++ b/site/src/routes/examples/[slug].json.js @@ -6,16 +6,16 @@ const cache = new Map(); export function get(req, res) { const { slug } = req.params; - try { - let example = cache.get(slug); + let example = cache.get(slug); - if (!example || process.env.NODE_ENV !== 'production') { - example = get_example(slug); - cache.set(slug, example); - } + if (!example || process.env.NODE_ENV !== 'production') { + example = get_example(slug); + if (example) cache.set(slug, example); + } + if (example) { send(res, 200, example); - } catch (err) { + } else { send(res, 404, { error: 'not found' }); diff --git a/site/src/routes/examples/_examples.js b/site/src/routes/examples/_examples.js index bf23769500..e4580d7fda 100644 --- a/site/src/routes/examples/_examples.js +++ b/site/src/routes/examples/_examples.js @@ -35,7 +35,7 @@ export function get_example(slug) { const dir = lookup.get(slug); const title = titles.get(slug); - if (!dir || !title) throw { status: 404, message: 'not found' }; + if (!dir || !title) return null; const files = fs.readdirSync(`content/examples/${dir}`) .filter(name => name[0] !== '.' && name !== 'meta.json') diff --git a/site/src/routes/gist/[id].js b/site/src/routes/gist/[id].js deleted file mode 100644 index 9e237d7b39..0000000000 --- a/site/src/routes/gist/[id].js +++ /dev/null @@ -1,66 +0,0 @@ -import fetch from 'node-fetch'; -import { body } from './_utils.js'; -import send from '@polka/send'; - -export async function get(req, res) { - const { id } = req.params; - - const headers = {}; - const user = req.session && req.session.passport && req.session.passport.user; - if (user) { - headers.Authorization = `token ${user.token}`; - } - - const r = await fetch(`https://api.github.com/gists/${id}`, { - headers - }); - - const result = await r.json(); - - if (r.status === 200) { - send(res, 200, { - id: result.id, - description: result.description, - owner: result.owner, - html_url: result.html_url, - files: result.files - }); - } else { - send(res, r.status, result); - } -} - -export async function patch(req, res) { - const user = req.session && req.session.passport && req.session.passport.user; - - if (!user) { - return send(res, 403, { error: 'unauthorized' }); - } - - try { - const { description, files } = await body(req); - - const r = await fetch(`https://api.github.com/gists/${req.params.id}`, { - method: 'PATCH', - headers: { - Authorization: `token ${user.token}` - }, - body: JSON.stringify({ - description, - files - }) - }); - - if (r.status === 200) { - send(res, 200, { ok: true }); - } else { - send(res, r.status, await r.text(), { - 'Content-Type': 'application/json' - }); - } - } catch (err) { - send(res, 500, { - error: err.message - }); - } -} diff --git a/site/src/routes/gist/create.js b/site/src/routes/gist/create.js deleted file mode 100644 index d67ea9b313..0000000000 --- a/site/src/routes/gist/create.js +++ /dev/null @@ -1,59 +0,0 @@ -import fetch from 'node-fetch'; -import { body } from './_utils.js'; -import send from '@polka/send'; - -export async function post(req, res) { - const user = req.session.passport && req.session.passport.user; - - if (!user) { - return send(res, 403, { error: 'unauthorized' }); - } - - try { - const { name, components } = await body(req); - - const files = { - 'meta.json': { - content: JSON.stringify({ - svelte: true - }, null, ' ') - }, - 'README.md': { - content: `Created with [svelte.dev/repl](https://svelte.dev/repl)` - } - }; - components.forEach(component => { - const file = `${component.name}.${component.type}`; - if (!component.source.trim()) { - throw new Error(`GitHub does not allow saving gists with empty files - ${file}`); - } - files[file] = { content: component.source }; - }); - - const r = await fetch(`https://api.github.com/gists`, { - method: 'POST', - headers: { - Authorization: `token ${user.token}` - }, - body: JSON.stringify({ - description: name, - files, - public: false - }) - }); - - const gist = await r.json(); - - send(res, r.status, { - id: gist.id, - description: gist.description, - owner: gist.owner, - html_url: gist.html_url, - files: gist.files - }); - } catch (err) { - send(res, 500, { - error: err.message - }); - } -} diff --git a/site/src/routes/repl/_components/AppControls/UserMenu.svelte b/site/src/routes/repl/[id]/_components/AppControls/UserMenu.svelte similarity index 90% rename from site/src/routes/repl/_components/AppControls/UserMenu.svelte rename to site/src/routes/repl/[id]/_components/AppControls/UserMenu.svelte index bb86371ed6..1404c1d5fc 100644 --- a/site/src/routes/repl/_components/AppControls/UserMenu.svelte +++ b/site/src/routes/repl/[id]/_components/AppControls/UserMenu.svelte @@ -1,15 +1,15 @@