From 2dfc264bf8ddecef1e2468447ded544cf8741169 Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Sun, 19 Sep 2021 12:30:22 -0600 Subject: [PATCH 001/126] ui: tweaks to Editor --- package.json | 39 +++--- .../scripts/components/elements/Editor.tsx | 46 +++---- yarn.lock | 113 +++++++++--------- 3 files changed, 97 insertions(+), 101 deletions(-) diff --git a/package.json b/package.json index b583f1d26..0c7cfd316 100644 --- a/package.json +++ b/package.json @@ -11,34 +11,33 @@ }, "dependencies": { "@": "link:./resources/scripts", - "@codemirror/autocomplete": "^0.19.3", + "@codemirror/autocomplete": "^0.19.0", "@codemirror/closebrackets": "^0.19.0", - "@codemirror/commands": "^0.19.2", + "@codemirror/commands": "^0.19.0", "@codemirror/comment": "^0.19.0", "@codemirror/fold": "^0.19.0", - "@codemirror/gutter": "^0.19.1", - "@codemirror/highlight": "^0.19.4", + "@codemirror/gutter": "^0.19.0", + "@codemirror/highlight": "^0.19.0", "@codemirror/history": "^0.19.0", - "@codemirror/lang-cpp": "^0.19.1", - "@codemirror/lang-css": "^0.19.1", - "@codemirror/lang-html": "^0.19.1", - "@codemirror/lang-java": "^0.19.1", - "@codemirror/lang-javascript": "^0.19.1", - "@codemirror/lang-json": "^0.19.1", - "@codemirror/lang-markdown": "^0.19.1", - "@codemirror/lang-rust": "^0.19.1", - "@codemirror/lang-sql": "^0.19.3", - "@codemirror/lang-xml": "^0.19.1", - "@codemirror/language": "^0.19.2", + "@codemirror/lang-cpp": "^0.19.0", + "@codemirror/lang-css": "^0.19.0", + "@codemirror/lang-html": "^0.19.0", + "@codemirror/lang-java": "^0.19.0", + "@codemirror/lang-javascript": "^0.19.0", + "@codemirror/lang-json": "^0.19.0", + "@codemirror/lang-markdown": "^0.19.0", + "@codemirror/lang-rust": "^0.19.0", + "@codemirror/lang-sql": "^0.19.0", + "@codemirror/lang-xml": "^0.19.0", + "@codemirror/language": "^0.19.0", "@codemirror/legacy-modes": "^0.19.0", "@codemirror/lint": "^0.19.0", - "@codemirror/matchbrackets": "^0.19.1", + "@codemirror/matchbrackets": "^0.19.0", "@codemirror/rectangular-selection": "^0.19.0", "@codemirror/search": "^0.19.0", - "@codemirror/state": "^0.19.1", - "@codemirror/stream-parser": "^0.19.1", - "@codemirror/theme-one-dark": "^0.19.0", - "@codemirror/view": "^0.19.4", + "@codemirror/state": "^0.19.0", + "@codemirror/stream-parser": "^0.19.0", + "@codemirror/view": "^0.19.0", "@fortawesome/fontawesome-svg-core": "^1.2.36", "@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4", diff --git a/resources/scripts/components/elements/Editor.tsx b/resources/scripts/components/elements/Editor.tsx index 5fa2dfe81..6666ac8e4 100644 --- a/resources/scripts/components/elements/Editor.tsx +++ b/resources/scripts/components/elements/Editor.tsx @@ -15,25 +15,25 @@ import { Compartment, Extension, EditorState } from '@codemirror/state'; import { StreamLanguage, StreamParser } from '@codemirror/stream-parser'; import { keymap, highlightSpecialChars, drawSelection, highlightActiveLine, EditorView } from '@codemirror/view'; import { clike } from '@codemirror/legacy-modes/mode/clike'; -import { cppLanguage } from '@codemirror/lang-cpp'; -import { cssLanguage } from '@codemirror/lang-css'; +import { cpp } from '@codemirror/lang-cpp'; +import { css } from '@codemirror/lang-css'; import { Cassandra, MariaSQL, MSSQL, MySQL, PostgreSQL, sql, SQLite, StandardSQL } from '@codemirror/lang-sql'; import { diff } from '@codemirror/legacy-modes/mode/diff'; import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile'; import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; import { go } from '@codemirror/legacy-modes/mode/go'; -import { htmlLanguage } from '@codemirror/lang-html'; +import { html } from '@codemirror/lang-html'; import { http } from '@codemirror/legacy-modes/mode/http'; -import { javascriptLanguage, typescriptLanguage } from '@codemirror/lang-javascript'; -import { jsonLanguage } from '@codemirror/lang-json'; +import { javascript, typescriptLanguage } from '@codemirror/lang-javascript'; +import { json } from '@codemirror/lang-json'; import { lua } from '@codemirror/legacy-modes/mode/lua'; import { properties } from '@codemirror/legacy-modes/mode/properties'; import { python } from '@codemirror/legacy-modes/mode/python'; import { ruby } from '@codemirror/legacy-modes/mode/ruby'; -import { rustLanguage } from '@codemirror/lang-rust'; +import { rust } from '@codemirror/lang-rust'; import { shell } from '@codemirror/legacy-modes/mode/shell'; import { toml } from '@codemirror/legacy-modes/mode/toml'; -import { xmlLanguage } from '@codemirror/lang-xml'; +import { xml } from '@codemirror/lang-xml'; import { yaml } from '@codemirror/legacy-modes/mode/yaml'; import React, { useCallback, useEffect, useState } from 'react'; import tw, { styled, TwStyle } from 'twin.macro'; @@ -42,29 +42,29 @@ import { ayuMirage } from '@/components/elements/EditorTheme'; type EditorMode = LanguageSupport | LRLanguage | StreamParser; export interface Mode { - name: string, - mime: string, - mimes?: string[], - mode?: EditorMode, - ext?: string[], - alias?: string[], - file?: RegExp, + name: string; + mime: string; + mimes?: string[]; + mode?: EditorMode; + ext?: string[]; + alias?: string[]; + file?: RegExp; } export const modes: Mode[] = [ { name: 'C', mime: 'text/x-csrc', mode: clike({}), ext: [ 'c', 'h', 'ino' ] }, - { name: 'C++', mime: 'text/x-c++src', mode: cppLanguage, ext: [ 'cpp', 'c++', 'cc', 'cxx', 'hpp', 'h++', 'hh', 'hxx' ], alias: [ 'cpp' ] }, + { name: 'C++', mime: 'text/x-c++src', mode: cpp(), ext: [ 'cpp', 'c++', 'cc', 'cxx', 'hpp', 'h++', 'hh', 'hxx' ], alias: [ 'cpp' ] }, { name: 'C#', mime: 'text/x-csharp', mode: clike({}), ext: [ 'cs' ], alias: [ 'csharp', 'cs' ] }, - { name: 'CSS', mime: 'text/css', mode: cssLanguage, ext: [ 'css' ] }, + { name: 'CSS', mime: 'text/css', mode: css(), ext: [ 'css' ] }, { name: 'CQL', mime: 'text/x-cassandra', mode: sql({ dialect: Cassandra }), ext: [ 'cql' ] }, { name: 'Diff', mime: 'text/x-diff', mode: diff, ext: [ 'diff', 'patch' ] }, { name: 'Dockerfile', mime: 'text/x-dockerfile', mode: dockerFile, file: /^Dockerfile$/ }, { name: 'Git Markdown', mime: 'text/x-gfm', mode: markdown({ defaultCodeLanguage: markdownLanguage }), file: /^(readme|contributing|history|license).md$/i }, { name: 'Golang', mime: 'text/x-go', mode: go, ext: [ 'go' ] }, - { name: 'HTML', mime: 'text/html', mode: htmlLanguage, ext: [ 'html', 'htm', 'handlebars', 'hbs' ], alias: [ 'xhtml' ] }, + { name: 'HTML', mime: 'text/html', mode: html(), ext: [ 'html', 'htm', 'handlebars', 'hbs' ], alias: [ 'xhtml' ] }, { name: 'HTTP', mime: 'message/http', mode: http }, - { name: 'JavaScript', mime: 'text/javascript', mimes: [ 'text/javascript', 'text/ecmascript', 'application/javascript', 'application/x-javascript', 'application/ecmascript' ], mode: javascriptLanguage, ext: [ 'js' ], alias: [ 'ecmascript', 'js', 'node' ] }, - { name: 'JSON', mime: 'application/json', mimes: [ 'application/json', 'application/x-json' ], mode: jsonLanguage, ext: [ 'json', 'map' ], alias: [ 'json5' ] }, + { name: 'JavaScript', mime: 'text/javascript', mimes: [ 'text/javascript', 'text/ecmascript', 'application/javascript', 'application/x-javascript', 'application/ecmascript' ], mode: javascript(), ext: [ 'js' ], alias: [ 'ecmascript', 'js', 'node' ] }, + { name: 'JSON', mime: 'application/json', mimes: [ 'application/json', 'application/x-json' ], mode: json(), ext: [ 'json', 'json5', 'map' ], alias: [ 'json5' ] }, { name: 'Lua', mime: 'text/x-lua', mode: lua, ext: [ 'lua' ] }, { name: 'Markdown', mime: 'text/x-markdown', mode: markdown({ defaultCodeLanguage: markdownLanguage }), ext: [ 'markdown', 'md', 'mkd' ] }, { name: 'MariaDB', mime: 'text/x-mariadb', mode: sql({ dialect: MariaSQL }) }, @@ -75,15 +75,15 @@ export const modes: Mode[] = [ { name: 'Properties', mime: 'text/x-properties', mode: properties, ext: [ 'properties', 'ini', 'in' ], alias: [ 'ini', 'properties' ] }, { name: 'Python', mime: 'text/x-python', mode: python, ext: [ 'BUILD', 'bzl', 'py', 'pyw' ], file: /^(BUCK|BUILD)$/ }, { name: 'Ruby', mime: 'text/x-ruby', mode: ruby, ext: [ 'rb' ], alias: [ 'jruby', 'macruby', 'rake', 'rb', 'rbx' ] }, - { name: 'Rust', mime: 'text/x-rustsrc', mode: rustLanguage, ext: [ 'rs' ] }, - { name: 'Sass', mime: 'text/x-sass', mode: cssLanguage, ext: [ 'sass' ] }, - { name: 'SCSS', mime: 'text/x-scss', mode: cssLanguage, ext: [ 'scss' ] }, + { name: 'Rust', mime: 'text/x-rustsrc', mode: rust(), ext: [ 'rs' ] }, + { name: 'Sass', mime: 'text/x-sass', mode: css(), ext: [ 'sass' ] }, + { name: 'SCSS', mime: 'text/x-scss', mode: css(), ext: [ 'scss' ] }, { name: 'Shell', mime: 'text/x-sh', mimes: [ 'text/x-sh', 'application/x-sh' ], mode: shell, ext: [ 'sh', 'ksh', 'bash' ], alias: [ 'bash', 'sh', 'zsh' ], file: /^PKGBUILD$/ }, { name: 'SQL', mime: 'text/x-sql', mode: sql({ dialect: StandardSQL }), ext: [ 'sql' ] }, { name: 'SQLite', mime: 'text/x-sqlite', mode: sql({ dialect: SQLite }) }, { name: 'TOML', mime: 'text/x-toml', mode: toml, ext: [ 'toml' ] }, { name: 'TypeScript', mime: 'application/typescript', mode: typescriptLanguage, ext: [ 'ts' ], alias: [ 'ts' ] }, - { name: 'XML', mime: 'application/xml', mimes: [ 'application/xml', 'text/xml' ], mode: xmlLanguage, ext: [ 'xml', 'xsl', 'xsd', 'svg' ], alias: [ 'rss', 'wsdl', 'xsd' ] }, + { name: 'XML', mime: 'application/xml', mimes: [ 'application/xml', 'text/xml' ], mode: xml(), ext: [ 'xml', 'xsl', 'xsd', 'svg' ], alias: [ 'rss', 'wsdl', 'xsd' ] }, { name: 'YAML', mime: 'text/x-yaml', mimes: [ 'text/x-yaml', 'text/yaml' ], mode: yaml, ext: [ 'yaml', 'yml' ], alias: [ 'yml' ] }, ]; diff --git a/yarn.lock b/yarn.lock index 4293c74a9..45a407243 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1646,7 +1646,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/autocomplete@npm:^0.19.0, @codemirror/autocomplete@npm:^0.19.3": +"@codemirror/autocomplete@npm:^0.19.0": version: 0.19.3 resolution: "@codemirror/autocomplete@npm:0.19.3" dependencies: @@ -1673,17 +1673,17 @@ __metadata: languageName: node linkType: hard -"@codemirror/commands@npm:^0.19.2": - version: 0.19.2 - resolution: "@codemirror/commands@npm:0.19.2" +"@codemirror/commands@npm:^0.19.0": + version: 0.19.4 + resolution: "@codemirror/commands@npm:0.19.4" dependencies: "@codemirror/language": ^0.19.0 "@codemirror/matchbrackets": ^0.19.0 - "@codemirror/state": ^0.19.0 + "@codemirror/state": ^0.19.2 "@codemirror/text": ^0.19.0 "@codemirror/view": ^0.19.0 "@lezer/common": ^0.15.0 - checksum: d47c9e7bc1eba7c18e0745cd7f303932a058ad99b07ffb32f0bf8cb037a0a9303d7319bf94475810f647692d37d7eb5d3adfbf0e6000d46906dd62a0644ee34c + checksum: f223310d77ab824c18305cf6880debf358648e239fee0f97c2c7add100dc58da90fd75e98d4095c5854891daa3fa0ad8c87d6155f60b706abf2664051362da13 languageName: node linkType: hard @@ -1711,7 +1711,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/gutter@npm:^0.19.0, @codemirror/gutter@npm:^0.19.1": +"@codemirror/gutter@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/gutter@npm:0.19.1" dependencies: @@ -1722,7 +1722,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/highlight@npm:^0.19.0, @codemirror/highlight@npm:^0.19.4": +"@codemirror/highlight@npm:^0.19.0": version: 0.19.4 resolution: "@codemirror/highlight@npm:0.19.4" dependencies: @@ -1746,7 +1746,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-cpp@npm:^0.19.1": +"@codemirror/lang-cpp@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-cpp@npm:0.19.1" dependencies: @@ -1757,7 +1757,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-css@npm:^0.19.0, @codemirror/lang-css@npm:^0.19.1": +"@codemirror/lang-css@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-css@npm:0.19.1" dependencies: @@ -1770,7 +1770,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-html@npm:^0.19.0, @codemirror/lang-html@npm:^0.19.1": +"@codemirror/lang-html@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-html@npm:0.19.1" dependencies: @@ -1786,7 +1786,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-java@npm:^0.19.1": +"@codemirror/lang-java@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-java@npm:0.19.1" dependencies: @@ -1797,7 +1797,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-javascript@npm:^0.19.0, @codemirror/lang-javascript@npm:^0.19.1": +"@codemirror/lang-javascript@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-javascript@npm:0.19.1" dependencies: @@ -1812,7 +1812,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-json@npm:^0.19.1": +"@codemirror/lang-json@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-json@npm:0.19.1" dependencies: @@ -1823,7 +1823,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-markdown@npm:^0.19.1": +"@codemirror/lang-markdown@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-markdown@npm:0.19.1" dependencies: @@ -1838,7 +1838,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-rust@npm:^0.19.1": +"@codemirror/lang-rust@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-rust@npm:0.19.1" dependencies: @@ -1849,7 +1849,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-sql@npm:^0.19.3": +"@codemirror/lang-sql@npm:^0.19.0": version: 0.19.3 resolution: "@codemirror/lang-sql@npm:0.19.3" dependencies: @@ -1862,7 +1862,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-xml@npm:^0.19.1": +"@codemirror/lang-xml@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/lang-xml@npm:0.19.1" dependencies: @@ -1876,7 +1876,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/language@npm:^0.19.0, @codemirror/language@npm:^0.19.2": +"@codemirror/language@npm:^0.19.0": version: 0.19.2 resolution: "@codemirror/language@npm:0.19.2" dependencies: @@ -1911,7 +1911,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/matchbrackets@npm:^0.19.0, @codemirror/matchbrackets@npm:^0.19.1": +"@codemirror/matchbrackets@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/matchbrackets@npm:0.19.1" dependencies: @@ -1954,20 +1954,20 @@ __metadata: linkType: hard "@codemirror/search@npm:^0.19.0": - version: 0.19.0 - resolution: "@codemirror/search@npm:0.19.0" + version: 0.19.2 + resolution: "@codemirror/search@npm:0.19.2" dependencies: "@codemirror/panel": ^0.19.0 "@codemirror/rangeset": ^0.19.0 - "@codemirror/state": ^0.19.0 + "@codemirror/state": ^0.19.2 "@codemirror/text": ^0.19.0 "@codemirror/view": ^0.19.0 crelt: ^1.0.5 - checksum: 88751f17bcb0ccffed8ae6d78df4a48438bf2a6dc6254a90a53b2971c7af5073be7bdc5243e4621d42938ac97b060aceb68c28aa22f78f42f1266c0ede605f12 + checksum: 67555a427fb7a9cb35266ff629f9cec0e3b5654f6813957b452e09504349ea2e021d8bb88bf6adef6908c95c7a3e850148fe0130f044486fb1ed527793592865 languageName: node linkType: hard -"@codemirror/state@npm:^0.19.0, @codemirror/state@npm:^0.19.1": +"@codemirror/state@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/state@npm:0.19.1" dependencies: @@ -1976,7 +1976,16 @@ __metadata: languageName: node linkType: hard -"@codemirror/stream-parser@npm:^0.19.0, @codemirror/stream-parser@npm:^0.19.1": +"@codemirror/state@npm:^0.19.2": + version: 0.19.2 + resolution: "@codemirror/state@npm:0.19.2" + dependencies: + "@codemirror/text": ^0.19.0 + checksum: 6460ff45d8ce20812a9abcb035a3e5f2a4adcb837c0efd00151b07c8e0bf617f6fdcf7668982b76c8e7bb447b0a83e7b8308817dac754c190c9495b49289bcaf + languageName: node + linkType: hard + +"@codemirror/stream-parser@npm:^0.19.0": version: 0.19.1 resolution: "@codemirror/stream-parser@npm:0.19.1" dependencies: @@ -1997,17 +2006,6 @@ __metadata: languageName: node linkType: hard -"@codemirror/theme-one-dark@npm:^0.19.0": - version: 0.19.0 - resolution: "@codemirror/theme-one-dark@npm:0.19.0" - dependencies: - "@codemirror/highlight": ^0.19.0 - "@codemirror/state": ^0.19.0 - "@codemirror/view": ^0.19.0 - checksum: 7116d5c66bc3a12f7f05d0cd7734c62b5efb261943538ceb0220acb3444efee05737422ae1ee34a3dfdccd02b2956add2cc23cdf0d9b1db17fd66f15b2e69517 - languageName: node - linkType: hard - "@codemirror/tooltip@npm:^0.19.0": version: 0.19.2 resolution: "@codemirror/tooltip@npm:0.19.2" @@ -2018,7 +2016,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/view@npm:^0.19.0, @codemirror/view@npm:^0.19.4": +"@codemirror/view@npm:^0.19.0": version: 0.19.4 resolution: "@codemirror/view@npm:0.19.4" dependencies: @@ -9912,34 +9910,33 @@ fsevents@^1.2.7: "@babel/preset-react": ^7.14.5 "@babel/preset-typescript": ^7.14.5 "@babel/runtime": ^7.14.5 - "@codemirror/autocomplete": ^0.19.3 + "@codemirror/autocomplete": ^0.19.0 "@codemirror/closebrackets": ^0.19.0 - "@codemirror/commands": ^0.19.2 + "@codemirror/commands": ^0.19.0 "@codemirror/comment": ^0.19.0 "@codemirror/fold": ^0.19.0 - "@codemirror/gutter": ^0.19.1 - "@codemirror/highlight": ^0.19.4 + "@codemirror/gutter": ^0.19.0 + "@codemirror/highlight": ^0.19.0 "@codemirror/history": ^0.19.0 - "@codemirror/lang-cpp": ^0.19.1 - "@codemirror/lang-css": ^0.19.1 - "@codemirror/lang-html": ^0.19.1 - "@codemirror/lang-java": ^0.19.1 - "@codemirror/lang-javascript": ^0.19.1 - "@codemirror/lang-json": ^0.19.1 - "@codemirror/lang-markdown": ^0.19.1 - "@codemirror/lang-rust": ^0.19.1 - "@codemirror/lang-sql": ^0.19.3 - "@codemirror/lang-xml": ^0.19.1 - "@codemirror/language": ^0.19.2 + "@codemirror/lang-cpp": ^0.19.0 + "@codemirror/lang-css": ^0.19.0 + "@codemirror/lang-html": ^0.19.0 + "@codemirror/lang-java": ^0.19.0 + "@codemirror/lang-javascript": ^0.19.0 + "@codemirror/lang-json": ^0.19.0 + "@codemirror/lang-markdown": ^0.19.0 + "@codemirror/lang-rust": ^0.19.0 + "@codemirror/lang-sql": ^0.19.0 + "@codemirror/lang-xml": ^0.19.0 + "@codemirror/language": ^0.19.0 "@codemirror/legacy-modes": ^0.19.0 "@codemirror/lint": ^0.19.0 - "@codemirror/matchbrackets": ^0.19.1 + "@codemirror/matchbrackets": ^0.19.0 "@codemirror/rectangular-selection": ^0.19.0 "@codemirror/search": ^0.19.0 - "@codemirror/state": ^0.19.1 - "@codemirror/stream-parser": ^0.19.1 - "@codemirror/theme-one-dark": ^0.19.0 - "@codemirror/view": ^0.19.4 + "@codemirror/state": ^0.19.0 + "@codemirror/stream-parser": ^0.19.0 + "@codemirror/view": ^0.19.0 "@fortawesome/fontawesome-svg-core": ^1.2.36 "@fortawesome/free-brands-svg-icons": ^5.15.4 "@fortawesome/free-regular-svg-icons": ^5.15.4 From 4a84c36009be10dbd83051ac1771662c056e4977 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 21 Sep 2021 21:30:08 -0700 Subject: [PATCH 002/126] Fix security vulnerability when authenticating a two-factor authentication token for a user See associated security advisory for technical details on the content of this security fix. GHSA ID: GHSA-5vfx-8w6m-h3v4 --- .../Auth/AbstractLoginController.php | 31 ++--- .../Auth/LoginCheckpointController.php | 107 +++++++++--------- app/Http/Controllers/Auth/LoginController.php | 56 ++++----- 3 files changed, 85 insertions(+), 109 deletions(-) diff --git a/app/Http/Controllers/Auth/AbstractLoginController.php b/app/Http/Controllers/Auth/AbstractLoginController.php index 601cdc142..e50a8050f 100644 --- a/app/Http/Controllers/Auth/AbstractLoginController.php +++ b/app/Http/Controllers/Auth/AbstractLoginController.php @@ -7,7 +7,7 @@ use Pterodactyl\Models\User; use Illuminate\Auth\AuthManager; use Illuminate\Http\JsonResponse; use Illuminate\Auth\Events\Failed; -use Illuminate\Contracts\Config\Repository; +use Illuminate\Container\Container; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; use Illuminate\Contracts\Auth\Authenticatable; @@ -17,6 +17,8 @@ abstract class AbstractLoginController extends Controller { use AuthenticatesUsers; + protected AuthManager $auth; + /** * Lockout time for failed login requests. * @@ -38,26 +40,14 @@ abstract class AbstractLoginController extends Controller */ protected $redirectTo = '/'; - /** - * @var \Illuminate\Auth\AuthManager - */ - protected $auth; - - /** - * @var \Illuminate\Contracts\Config\Repository - */ - protected $config; - /** * LoginController constructor. */ - public function __construct(AuthManager $auth, Repository $config) + public function __construct() { - $this->lockoutTime = $config->get('auth.lockout.time'); - $this->maxLoginAttempts = $config->get('auth.lockout.attempts'); - - $this->auth = $auth; - $this->config = $config; + $this->lockoutTime = config('auth.lockout.time'); + $this->maxLoginAttempts = config('auth.lockout.attempts'); + $this->auth = Container::getInstance()->make(AuthManager::class); } /** @@ -84,12 +74,14 @@ abstract class AbstractLoginController extends Controller */ protected function sendLoginResponse(User $user, Request $request): JsonResponse { + $request->session()->remove('auth_confirmation_token'); $request->session()->regenerate(); + $this->clearLoginAttempts($request); $this->auth->guard()->login($user, true); - return JsonResponse::create([ + return new JsonResponse([ 'data' => [ 'complete' => true, 'intended' => $this->redirectPath(), @@ -101,7 +93,8 @@ abstract class AbstractLoginController extends Controller /** * Determine if the user is logging in using an email or username,. * - * @param string $input + * @param string|null $input + * @return string */ protected function getField(string $input = null): string { diff --git a/app/Http/Controllers/Auth/LoginCheckpointController.php b/app/Http/Controllers/Auth/LoginCheckpointController.php index 3710da3a2..fdb5b7e13 100644 --- a/app/Http/Controllers/Auth/LoginCheckpointController.php +++ b/app/Http/Controllers/Auth/LoginCheckpointController.php @@ -2,64 +2,36 @@ namespace Pterodactyl\Http\Controllers\Auth; +use Carbon\CarbonInterface; +use Carbon\CarbonImmutable; use Pterodactyl\Models\User; -use Illuminate\Auth\AuthManager; use Illuminate\Http\JsonResponse; use PragmaRX\Google2FA\Google2FA; -use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Database\Eloquent\ModelNotFoundException; use Pterodactyl\Http\Requests\Auth\LoginCheckpointRequest; -use Illuminate\Contracts\Cache\Repository as CacheRepository; -use Pterodactyl\Contracts\Repository\UserRepositoryInterface; -use Pterodactyl\Repositories\Eloquent\RecoveryTokenRepository; +use Illuminate\Contracts\Validation\Factory as ValidationFactory; class LoginCheckpointController extends AbstractLoginController { - /** - * @var \Illuminate\Contracts\Cache\Repository - */ - private $cache; + private const TOKEN_EXPIRED_MESSAGE = 'The authentication token provided has expired, please refresh the page and try again.'; - /** - * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface - */ - private $repository; + private ValidationFactory $validation; - /** - * @var \PragmaRX\Google2FA\Google2FA - */ - private $google2FA; + private Google2FA $google2FA; - /** - * @var \Illuminate\Contracts\Encryption\Encrypter - */ - private $encrypter; - - /** - * @var \Pterodactyl\Repositories\Eloquent\RecoveryTokenRepository - */ - private $recoveryTokenRepository; + private Encrypter $encrypter; /** * LoginCheckpointController constructor. */ - public function __construct( - AuthManager $auth, - Encrypter $encrypter, - Google2FA $google2FA, - Repository $config, - CacheRepository $cache, - RecoveryTokenRepository $recoveryTokenRepository, - UserRepositoryInterface $repository - ) { - parent::__construct($auth, $config); + public function __construct(Encrypter $encrypter, Google2FA $google2FA, ValidationFactory $validation) + { + parent::__construct(); $this->google2FA = $google2FA; - $this->cache = $cache; - $this->repository = $repository; $this->encrypter = $encrypter; - $this->recoveryTokenRepository = $recoveryTokenRepository; + $this->validation = $validation; } /** @@ -81,18 +53,20 @@ class LoginCheckpointController extends AbstractLoginController $this->sendLockoutResponse($request); } - $token = $request->input('confirmation_token'); + $details = $request->session()->get('auth_confirmation_token'); + if (!$this->hasValidSessionData($details)) { + $this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE); + } + + if (!hash_equals($request->input('confirmation_token') ?? '', $details['token_value'])) { + $this->sendFailedLoginResponse($request); + } + try { /** @var \Pterodactyl\Models\User $user */ - $user = User::query()->findOrFail($this->cache->get($token, 0)); + $user = User::query()->findOrFail($details['user_id']); } catch (ModelNotFoundException $exception) { - $this->incrementLoginAttempts($request); - - return $this->sendFailedLoginResponse( - $request, - null, - 'The authentication token provided has expired, please refresh the page and try again.' - ); + $this->sendFailedLoginResponse($request, null, self::TOKEN_EXPIRED_MESSAGE); } // Recovery tokens go through a slightly different pathway for usage. @@ -104,15 +78,11 @@ class LoginCheckpointController extends AbstractLoginController $decrypted = $this->encrypter->decrypt($user->totp_secret); if ($this->google2FA->verifyKey($decrypted, (string) $request->input('authentication_code') ?? '', config('pterodactyl.auth.2fa.window'))) { - $this->cache->delete($token); - return $this->sendLoginResponse($user, $request); } } - $this->incrementLoginAttempts($request); - - return $this->sendFailedLoginResponse($request, $user, !empty($recoveryToken) ? 'The recovery token provided is not valid.' : null); + $this->sendFailedLoginResponse($request, $user, !empty($recoveryToken) ? 'The recovery token provided is not valid.' : null); } /** @@ -135,4 +105,35 @@ class LoginCheckpointController extends AbstractLoginController return false; } + + /** + * Determines if the data provided from the session is valid or not. This + * will return false if the data is invalid, or if more time has passed than + * was configured when the session was written. + * + * @param array $data + * @return bool + */ + protected function hasValidSessionData(array $data): bool + { + $validator = $this->validation->make($data, [ + 'user_id' => 'required|integer|min:1', + 'token_value' => 'required|string', + 'expires_at' => 'required', + ]); + + if ($validator->fails()) { + return false; + } + + if (!$data['expires_at'] instanceof CarbonInterface) { + return false; + } + + if ($data['expires_at']->isBefore(CarbonImmutable::now())) { + return false; + } + + return true; + } } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index db74ab125..3c477c556 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -5,47 +5,24 @@ namespace Pterodactyl\Http\Controllers\Auth; use Carbon\CarbonImmutable; use Illuminate\Support\Str; use Illuminate\Http\Request; -use Illuminate\Auth\AuthManager; +use Pterodactyl\Models\User; use Illuminate\Http\JsonResponse; use Illuminate\Contracts\View\View; -use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\View\Factory as ViewFactory; -use Illuminate\Contracts\Cache\Repository as CacheRepository; -use Pterodactyl\Contracts\Repository\UserRepositoryInterface; -use Pterodactyl\Exceptions\Repository\RecordNotFoundException; +use Illuminate\Database\Eloquent\ModelNotFoundException; class LoginController extends AbstractLoginController { - /** - * @var \Illuminate\Contracts\View\Factory - */ - private $view; - - /** - * @var \Illuminate\Contracts\Cache\Repository - */ - private $cache; - - /** - * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface - */ - private $repository; + private ViewFactory $view; /** * LoginController constructor. */ - public function __construct( - AuthManager $auth, - Repository $config, - CacheRepository $cache, - UserRepositoryInterface $repository, - ViewFactory $view - ) { - parent::__construct($auth, $config); + public function __construct(ViewFactory $view) + { + parent::__construct(); $this->view = $view; - $this->cache = $cache; - $this->repository = $repository; } /** @@ -68,18 +45,18 @@ class LoginController extends AbstractLoginController */ public function login(Request $request): JsonResponse { - $username = $request->input('user'); - $useColumn = $this->getField($username); - if ($this->hasTooManyLoginAttempts($request)) { $this->fireLockoutEvent($request); $this->sendLockoutResponse($request); } try { - $user = $this->repository->findFirstWhere([[$useColumn, '=', $username]]); - } catch (RecordNotFoundException $exception) { - return $this->sendFailedLoginResponse($request); + $username = $request->input('user'); + + /** @var \Pterodactyl\Models\User $user */ + $user = User::query()->where($this->getField($username), $username)->firstOrFail(); + } catch (ModelNotFoundException $exception) { + $this->sendFailedLoginResponse($request); } // Ensure that the account is using a valid username and password before trying to @@ -87,12 +64,17 @@ class LoginController extends AbstractLoginController // a flaw in which you can discover if an account exists simply by seeing if you // can proceede to the next step in the login process. if (!password_verify($request->input('password'), $user->password)) { - return $this->sendFailedLoginResponse($request, $user); + $this->sendFailedLoginResponse($request, $user); } if ($user->use_totp) { $token = Str::random(64); - $this->cache->put($token, $user->id, CarbonImmutable::now()->addMinutes(5)); + + $request->session()->put('auth_confirmation_token', [ + 'user_id' => $user->id, + 'token_value' => $token, + 'expires_at' => CarbonImmutable::now()->addMinutes(5), + ]); return new JsonResponse([ 'data' => [ From c57eb2c9e6e31823669c4ec444afed9f3e156a5e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 21 Sep 2021 21:36:29 -0700 Subject: [PATCH 003/126] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b3da3007..f72f306f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This file is a running track of new features and fixes to each version of the pa This project follows [Semantic Versioning](http://semver.org) guidelines. +## v1.6.2 +### Fixed +* **[Security]** Fixes an authentication bypass vulerability that could allow a malicious actor to login as another user in the Panel without knowing that user's email or password. + ## v1.6.1 ### Fixed * Fixes server build modifications not being properly persisted to the database when edited. From 7239f0e33645361bcb2bc44495579536a681c8ce Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Fri, 1 Oct 2021 11:07:48 -0600 Subject: [PATCH 004/126] ui(admin): add egg variable elements --- .../components/admin/nests/eggs/EggRouter.tsx | 2 +- .../nests/eggs/EggVariablesContainer.tsx | 95 ++++++++++++++++++- .../scripts/components/elements/Checkbox.tsx | 43 ++++----- .../scripts/components/elements/Field.tsx | 42 ++++++-- .../scripts/components/elements/Label.tsx | 5 +- .../components/server/users/PermissionRow.tsx | 42 +++++++- 6 files changed, 185 insertions(+), 44 deletions(-) diff --git a/resources/scripts/components/admin/nests/eggs/EggRouter.tsx b/resources/scripts/components/admin/nests/eggs/EggRouter.tsx index 8ac6f15de..1d591869e 100644 --- a/resources/scripts/components/admin/nests/eggs/EggRouter.tsx +++ b/resources/scripts/components/admin/nests/eggs/EggRouter.tsx @@ -39,7 +39,7 @@ const EggRouter = () => { useEffect(() => { clearFlashes('egg'); - getEgg(Number(match.params?.id)) + getEgg(Number(match.params?.id), [ 'variables' ]) .then(egg => setEgg(egg)) .catch(error => { console.error(error); diff --git a/resources/scripts/components/admin/nests/eggs/EggVariablesContainer.tsx b/resources/scripts/components/admin/nests/eggs/EggVariablesContainer.tsx index 76a88ed33..41388a07e 100644 --- a/resources/scripts/components/admin/nests/eggs/EggVariablesContainer.tsx +++ b/resources/scripts/components/admin/nests/eggs/EggVariablesContainer.tsx @@ -1,11 +1,96 @@ +import { Form, Formik, useFormikContext } from 'formik'; import React from 'react'; +import tw from 'twin.macro'; +import { object } from 'yup'; +import { Egg, EggVariable } from '@/api/admin/eggs/getEgg'; import AdminBox from '@/components/admin/AdminBox'; -import { Egg } from '@/api/admin/eggs/getEgg'; +import Checkbox from '@/components/elements/Checkbox'; +import Field, { FieldRow, TextareaField } from '@/components/elements/Field'; +import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; + +function EggVariableForm ({ variable: { name } }: { variable: EggVariable }) { + const { isSubmitting } = useFormikContext(); -export default ({ egg }: { egg: Egg }) => { return ( - - {egg.name} + {name}

}> + + + + + + + + + + + + +
+ + + +
+ +
); -}; +} + +export default function EggVariablesContainer ({ egg }: { egg: Egg }) { + const submit = () => { + // + }; + + return ( + +
+
+ {egg.relations?.variables?.map(v => )} +
+
+
+ ); +} diff --git a/resources/scripts/components/elements/Checkbox.tsx b/resources/scripts/components/elements/Checkbox.tsx index 790536489..b3954e708 100644 --- a/resources/scripts/components/elements/Checkbox.tsx +++ b/resources/scripts/components/elements/Checkbox.tsx @@ -1,42 +1,35 @@ +import Label from '@/components/elements/Label'; import React from 'react'; import { Field, FieldProps } from 'formik'; import Input from '@/components/elements/Input'; +import tw from 'twin.macro'; interface Props { name: string; - value: string; + label?: string; className?: string; } -type OmitFields = 'ref' | 'name' | 'value' | 'type' | 'checked' | 'onClick' | 'onChange'; +type OmitFields = 'ref' | 'name' | 'value' | 'type'; type InputProps = Omit; -const Checkbox = ({ name, value, className, ...props }: Props & InputProps) => ( +const Checkbox = ({ name, label, className, ...props }: Props & InputProps) => ( - {({ field, form }: FieldProps) => { - if (!Array.isArray(field.value)) { - console.error('Attempting to mount a checkbox using a field value that is not an array.'); - - return null; - } - + {({ field }: FieldProps) => { return ( - form.setFieldTouched(field.name, true)} - onChange={e => { - const set = new Set(field.value); - set.has(value) ? set.delete(value) : set.add(value); - - field.onChange(e); - form.setFieldValue(field.name, Array.from(set)); - }} - /> +
+ + {label && +
+ +
} +
); }}
diff --git a/resources/scripts/components/elements/Field.tsx b/resources/scripts/components/elements/Field.tsx index 5840983ed..6d35e6b89 100644 --- a/resources/scripts/components/elements/Field.tsx +++ b/resources/scripts/components/elements/Field.tsx @@ -1,9 +1,9 @@ -import React, { forwardRef } from 'react'; import { Field as FormikField, FieldProps } from 'formik'; +import React, { forwardRef } from 'react'; +import tw, { styled } from 'twin.macro'; import Input, { Textarea } from '@/components/elements/Input'; -import Label from '@/components/elements/Label'; import InputError from '@/components/elements/InputError'; -import tw from 'twin.macro'; +import Label from '@/components/elements/Label'; interface OwnProps { name: string; @@ -11,15 +11,17 @@ interface OwnProps { label?: string; description?: string; validate?: (value: any) => undefined | string | Promise; + + className?: string; } type Props = OwnProps & Omit, 'name'>; -const Field = forwardRef(({ id, name, light = false, label, description, validate, ...props }, ref) => ( +const Field = forwardRef(({ id, name, light = false, label, description, validate, className, ...props }, ref) => ( { ({ field, form: { errors, touched } }: FieldProps) => ( -
+
{label &&
@@ -43,15 +45,17 @@ const Field = forwardRef(({ id, name, light = false, la )); Field.displayName = 'Field'; -type Props2 = OwnProps & Omit, 'name'>; +export default Field; -export const TextareaField = forwardRef( - function TextareaField ({ id, name, light = false, label, description, validate, ...props }, ref) { +type TextareaProps = OwnProps & Omit, 'name'>; + +export const TextareaField = forwardRef( + function TextareaField ({ id, name, light = false, label, description, validate, className, ...props }, ref) { return ( { ({ field, form: { errors, touched } }: FieldProps) => ( -
+
{label && }