diff --git a/.github/PULL_REQUEST_TEMPLATE/atomic-refactor-pull-request-for-issue-2119.md b/.github/PULL_REQUEST_TEMPLATE/atomic-refactor-pull-request-for-issue-2119.md new file mode 100644 index 000000000..ecd61f609 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/atomic-refactor-pull-request-for-issue-2119.md @@ -0,0 +1,23 @@ + + +# Description + + +This PR is for updating/adding a component following the atomic design pattern set out in #2119. + + + +--- + +Extra Info + + +- Component name in [kanban board](https://collab.owncast.tv/kanban/#/2/kanban/edit/omLI2N+LcnP+elmdT7qW9GHD/): `________` + +Checklist: +- [] The component follows the [design guide](../../web/components/_COMPONENT_HOW_TO.md). +- [] Moved the component to the correct `atoms` / `molecules` / `organisms` / `templates` directory. +- [] Added an explanation to this PR for any major changes you made. +- [] Replaced any [`defaultProps`](https://www.reactjstutorials.com/react-basics/17/react-default-props) with default args. +- [] Added a (short) JSDoc description to the component. +- [] Removed the component's Storybook description text with if it's not needed. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE/standard-pull-request.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE.md rename to .github/PULL_REQUEST_TEMPLATE/standard-pull-request.md diff --git a/.github/workflows/auto-comment-on-label.yaml b/.github/workflows/auto-comment-on-label.yaml new file mode 100644 index 000000000..2f5e7d0da --- /dev/null +++ b/.github/workflows/auto-comment-on-label.yaml @@ -0,0 +1,38 @@ +name: Add comment on good first issues +on: + issues: + types: + - labeled +jobs: + add-comment: + if: github.event.label.name == 'good first issue' || github.event.label.name == 'help wanted' || github.event.label.name == 'hacktoberfest' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Add comment + uses: peter-evans/create-or-update-comment@6fcd282399b3c9ad0bd9bd8025b8fb2c18b085dd + with: + issue-number: ${{ github.event.issue.number }} + body: | + ## Good First Issue + + This item was marked as a good first issue because of the following: + + - It's self contained as a single feature or change. + - Is clear when it's complete. + - You do not need deep knowledge of Owncast to accomplish it. + + + ### Next Steps + + 1. Comment on this issue before starting work so it can be assigned to you. Also, this issue may have been filed with limited detail or changes may have occurred that are worth sharing with you before you start work. + 2. Drop by our [community chat](https://owncast.rocket.chat/) if you'd like to be involved in more real-time discussion around Owncast to talk about this change. + 3. Follow the project's getting started tips to make sure you can [build and run the project from source](https://owncast.online/development). + + ### Notes + + - Current web work is taking place in the [`webv2` branch](https://github.com/owncast/owncast/tree/webv2) and it is very much work in progress. Read the [README](https://github.com/owncast/owncast/blob/webv2/web/README.md) for this branch to get the web project running. But it's mostly just a `npm install` and `npm run dev`. + - We use Storybook for testing and developing React components. `npm run storybook`. + - If you need to install the Go programming language to run the Owncast backend it's simple from [here](https://go.dev/dl/). + - Active contributors get an Owncast t-shirt! Ask about it if you feel like you've been contributing and haven't yet been given one. diff --git a/.github/workflows/automated-end-to-end-api.yaml b/.github/workflows/automated-end-to-end-api.yaml index 5f6402d5f..daa100e28 100644 --- a/.github/workflows/automated-end-to-end-api.yaml +++ b/.github/workflows/automated-end-to-end-api.yaml @@ -3,9 +3,7 @@ name: Automated API tests on: push: paths-ignore: - - 'web/**' - pull_request: - paths-ignore: + - 'webroot/**' - 'web/**' jobs: diff --git a/.github/workflows/docker-webv2.yaml b/.github/workflows/docker-webv2.yaml new file mode 100644 index 000000000..3c62b5306 --- /dev/null +++ b/.github/workflows/docker-webv2.yaml @@ -0,0 +1,42 @@ +# See https://docs.earthly.dev/ci-integration/vendor-specific-guides/gh-actions-integration +# for details. + +name: Build webv2 docker + +on: + workflow_dispatch: + schedule: + - cron: '0 3 * * *' + +jobs: + Docker: + runs-on: ubuntu-latest + steps: + - uses: earthly/actions-setup@v1 + with: + version: 'latest' # or pin to an specific version, e.g. "v0.6.10" + + - name: Earthly version + run: earthly --version + + - name: Log into GitHub Container Registry + env: + GH_CR_PAT: ${{ secrets.GH_CR_PAT }} + run: echo "${{ secrets.GH_CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin + if: env.GH_CR_PAT != null + + - name: Set up QEMU + id: qemu + uses: docker/setup-qemu-action@v2 + with: + image: tonistiigi/binfmt:latest + platforms: all + + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Checkout and build + if: env.GH_CR_PAT != null + env: + GH_CR_PAT: ${{ secrets.GH_CR_PAT }} + run: cd build/release && ./docker-webv2.sh diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml index a936b2fe6..adce3701c 100644 --- a/.github/workflows/go-lint.yml +++ b/.github/workflows/go-lint.yml @@ -5,6 +5,11 @@ on: - 'webroot/**' - 'web/**' + pull_request: + paths-ignore: + - 'webroot/**' + - 'web/**' + permissions: contents: read diff --git a/.github/workflows/javascript-formatting.yml b/.github/workflows/javascript-formatting.yml index 5934d2734..7128d7530 100644 --- a/.github/workflows/javascript-formatting.yml +++ b/.github/workflows/javascript-formatting.yml @@ -51,6 +51,7 @@ jobs: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} fetch-depth: 0 + pull: --rebase --autostash - name: Install Dependencies run: npm install diff --git a/auth/fediverse/fediverse.go b/auth/fediverse/fediverse.go index 404af3916..8fced2fb2 100644 --- a/auth/fediverse/fediverse.go +++ b/auth/fediverse/fediverse.go @@ -3,6 +3,7 @@ package fediverse import ( "crypto/rand" "io" + "strings" "time" ) @@ -37,7 +38,7 @@ func RegisterFediverseOTP(accessToken, userID, userDisplayName, account string) Code: code, UserID: userID, UserDisplayName: userDisplayName, - Account: account, + Account: strings.ToLower(account), Timestamp: time.Now(), } pendingAuthRequests[accessToken] = r diff --git a/auth/fediverse/fediverse_test.go b/auth/fediverse/fediverse_test.go index 912736d05..8b4059d9c 100644 --- a/auth/fediverse/fediverse_test.go +++ b/auth/fediverse/fediverse_test.go @@ -1,6 +1,9 @@ package fediverse -import "testing" +import ( + "strings" + "testing" +) const ( accessToken = "fake-access-token" @@ -58,3 +61,18 @@ func TestSingleOTPFlowRequest(t *testing.T) { t.Error("Second registration should not be permitted.") } } + +func TestAccountCaseInsensitive(t *testing.T) { + account := "Account" + accessToken := "another-fake-access-token" + r1, _ := RegisterFediverseOTP(accessToken, userID, userDisplayName, account) + _, reg1 := ValidateFediverseOTP(accessToken, r1.Code) + + // Simulate second auth with account in different case + r2, _ := RegisterFediverseOTP(accessToken, userID, userDisplayName, strings.ToUpper(account)) + _, reg2 := ValidateFediverseOTP(accessToken, r2.Code) + + if reg1.Account != reg2.Account { + t.Errorf("Account names should be case-insensitive: %s %s", reg1.Account, reg2.Account) + } +} diff --git a/build/javascript/package-lock.json b/build/javascript/package-lock.json index f729d856c..17ce5d227 100644 --- a/build/javascript/package-lock.json +++ b/build/javascript/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", + "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -317,14 +317,14 @@ } }, "browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "requires": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" } }, "bytes": { @@ -350,9 +350,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001381", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001381.tgz", - "integrity": "sha512-fEnkDOKpvp6qc+olg7+NzE1SqyfiyKf4uci7fAU38M3zxs0YOyKOxW/nMZ2l9sJbt7KZHcDIxUnbI0Iime7V4w==" + "version": "1.0.30001412", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", + "integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==" }, "chalk": { "version": "4.1.2", @@ -474,9 +474,9 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "css-declaration-sorter": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.0.tgz", - "integrity": "sha512-OGT677UGHJTAVMRhPO+HJ4oKln3wkBTwtDFH0ojbqm+MJm6xuDMHp2nkhh/ThaBqq20IbraBQSWKfSLNHQO9Og==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", "dev": true }, "css-select": { @@ -645,9 +645,9 @@ } }, "electron-to-chromium": { - "version": "1.4.225", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.225.tgz", - "integrity": "sha512-ICHvGaCIQR3P88uK8aRtx8gmejbVJyC6bB4LEC3anzBrIzdzC7aiZHY4iFfXhN4st6I7lMO0x4sgBHf/7kBvRw==" + "version": "1.4.262", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.262.tgz", + "integrity": "sha512-Ckn5haqmGh/xS8IbcgK3dnwAVnhDyo/WQnklWn6yaMucYTq7NNxwlGE8ElzEOnonzRLzUCo2Ot3vUb2GYUF2Hw==" }, "emoji-regex": { "version": "8.0.0", @@ -676,9 +676,9 @@ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -2076,9 +2076,9 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, "update-browserslist-db": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", - "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" diff --git a/build/release/docker-webv2.sh b/build/release/docker-webv2.sh new file mode 100755 index 000000000..b75a9d4c9 --- /dev/null +++ b/build/release/docker-webv2.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Docker build +# Must authenticate first: https://docs.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages +DOCKER_IMAGE="owncast" +DATE=$(date +"%Y%m%d") +TAG="webv2" +VERSION="${DATE}-${TAG}" +echo "Building Docker image ${DOCKER_IMAGE}..." + +# Change to the root directory of the repository +cd $(git rev-parse --show-toplevel) +git checkout webv2 + +earthly --ci --push +docker-all --image="ghcr.io/owncast/${DOCKER_IMAGE}" --tag=${TAG} --version="${VERSION}" diff --git a/controllers/auth/fediverse/fediverse.go b/controllers/auth/fediverse/fediverse.go index 6192e712e..51e70dfb6 100644 --- a/controllers/auth/fediverse/fediverse.go +++ b/controllers/auth/fediverse/fediverse.go @@ -7,7 +7,6 @@ import ( "github.com/owncast/owncast/activitypub" "github.com/owncast/owncast/auth" - "github.com/owncast/owncast/auth/fediverse" fediverseauth "github.com/owncast/owncast/auth/fediverse" "github.com/owncast/owncast/controllers" "github.com/owncast/owncast/core/chat" @@ -57,7 +56,7 @@ func VerifyFediverseOTPRequest(w http.ResponseWriter, r *http.Request) { return } accessToken := r.URL.Query().Get("accessToken") - valid, authRegistration := fediverse.ValidateFediverseOTP(accessToken, req.Code) + valid, authRegistration := fediverseauth.ValidateFediverseOTP(accessToken, req.Code) if !valid { w.WriteHeader(http.StatusForbidden) return @@ -99,5 +98,4 @@ func VerifyFediverseOTPRequest(w http.ResponseWriter, r *http.Request) { } controllers.WriteSimpleResponse(w, true, "") - w.WriteHeader(http.StatusOK) } diff --git a/core/chat/events.go b/core/chat/events.go index 824aef5c6..fa4d0b45c 100644 --- a/core/chat/events.go +++ b/core/chat/events.go @@ -36,7 +36,7 @@ func (s *Server) userNameChanged(eventData chatClientEvent) { normalizedName = strings.ToLower(normalizedName) if strings.Contains(normalizedName, proposedUsername) { // Denied. - log.Debugln(eventData.client.User.DisplayName, "blocked from changing name to", proposedUsername, "due to blocked name", normalizedName) + log.Debugln(logSanitize(eventData.client.User.DisplayName), "blocked from changing name to", logSanitize(proposedUsername), "due to blocked name", normalizedName) message := fmt.Sprintf("You cannot change your name to **%s**.", proposedUsername) s.sendActionToClient(eventData.client, message) @@ -160,3 +160,11 @@ func (s *Server) userMessageSent(eventData chatClientEvent) { eventData.client.MessageCount++ _lastSeenCache[event.User.ID] = time.Now() } + +func logSanitize(userValue string) string { + // strip carriage return and newline from user-submitted values to prevent log injection + sanitizedValue := strings.ReplaceAll(userValue, "\n", "") + sanitizedValue = strings.ReplaceAll(sanitizedValue, "\r", "") + + return fmt.Sprintf("userSuppliedValue(%s)", sanitizedValue) +} diff --git a/core/chat/server.go b/core/chat/server.go index babe332ea..d8692a8ca 100644 --- a/core/chat/server.go +++ b/core/chat/server.go @@ -362,7 +362,7 @@ func (s *Server) eventReceived(event chatClientEvent) { case events.UserColorChanged: s.userColorChanged(event) default: - log.Debugln(eventType, "event not found:", typecheck) + log.Debugln(logSanitize(fmt.Sprint(eventType)), "event not found:", logSanitize(fmt.Sprint(typecheck))) } } diff --git a/docs/api/index.html b/docs/api/index.html index 5f06847b6..700eac92e 100644 --- a/docs/api/index.html +++ b/docs/api/index.html @@ -13,27 +13,27 @@ }