Compare commits

..

No commits in common. "8e267afd3569a56c7dde813d278c55b021b8431f" and "40ba750c4bf1f3f5f8dff5af57b2db4b600f237f" have entirely different histories.

42 changed files with 1360 additions and 2124 deletions

View File

@ -551,7 +551,7 @@ steps:
# TODO: We should probably build all dependencies into a test image
- name: test-e2e
image: mcr.microsoft.com/playwright:v1.29.0-focal
image: mcr.microsoft.com/playwright:v1.28.0-focal
commands:
- curl -sLO https://go.dev/dl/go1.19.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.19.linux-amd64.tar.gz
- groupadd --gid 1001 gitea && useradd -m --gid 1001 --uid 1001 gitea

View File

@ -255,7 +255,7 @@ rules:
no-irregular-whitespace: [2]
no-iterator: [2]
no-label-var: [2]
no-labels: [0] # handled by no-restricted-syntax
no-labels: [0]
no-lone-blocks: [2]
no-lonely-if: [0]
no-loop-func: [0]
@ -335,7 +335,7 @@ rules:
no-void: [2]
no-warning-comments: [0]
no-whitespace-before-property: [2]
no-with: [0] # handled by no-restricted-syntax
no-with: [0]
nonblock-statement-body-position: [2]
object-curly-newline: [0]
object-curly-spacing: [2, never]
@ -495,7 +495,7 @@ rules:
unicorn/prefer-native-coercion-functions: [2]
unicorn/prefer-negative-index: [2]
unicorn/prefer-node-append: [0]
unicorn/prefer-node-protocol: [2]
unicorn/prefer-node-protocol: [0]
unicorn/prefer-node-remove: [0]
unicorn/prefer-number-properties: [0]
unicorn/prefer-object-from-entries: [2]

View File

@ -2,7 +2,7 @@
import imageminZopfli from 'imagemin-zopfli';
import {optimize} from 'svgo';
import {fabric} from 'fabric';
import {readFile, writeFile} from 'node:fs/promises';
import {readFile, writeFile} from 'fs/promises';
function exit(err) {
if (err) console.error(err);

View File

@ -1,9 +1,9 @@
#!/usr/bin/env node
import fastGlob from 'fast-glob';
import {optimize} from 'svgo';
import {parse} from 'node:path';
import {readFile, writeFile, mkdir} from 'node:fs/promises';
import {fileURLToPath} from 'node:url';
import {parse} from 'path';
import {readFile, writeFile, mkdir} from 'fs/promises';
import {fileURLToPath} from 'url';
const glob = (pattern) => fastGlob.sync(pattern, {
cwd: fileURLToPath(new URL('..', import.meta.url)),

View File

@ -1,36 +0,0 @@
---
date: "2022-12-19T21:26:00+08:00"
title: "Encrypted secrets"
slug: "secrets/overview"
draft: false
toc: false
menu:
sidebar:
parent: "secrets"
name: "Overview"
weight: 1
identifier: "overview"
---
# Encrypted secrets
Encrypted secrets allow you to store sensitive information in your organization or repository.
Secrets are available on Gitea 1.19+.
# Naming your secrets
The following rules apply to secret names:
Secret names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
Secret names must not start with the `GITHUB_` and `GITEA_` prefix.
Secret names must not start with a number.
Secret names are not case-sensitive.
Secret names must be unique at the level they are created at.
For example, a secret created at the repository level must have a unique name in that repository, and a secret created at the organization level must have a unique name at that level.
If a secret with the same name exists at multiple levels, the secret at the lowest level takes precedence. For example, if an organization-level secret has the same name as a repository-level secret, then the repository-level secret takes precedence.

View File

@ -442,8 +442,6 @@ var migrations = []Migration{
NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable),
// v235 -> v236
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
// v236 -> v237
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
}
// GetCurrentDBVersion returns the current db version

View File

@ -1,23 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_19 //nolint
import (
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/xorm"
)
func CreateSecretsTable(x *xorm.Engine) error {
type Secret struct {
ID int64
OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"`
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
}
return x.Sync(new(Secret))
}

View File

@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
@ -371,7 +370,6 @@ func DeleteOrganization(ctx context.Context, org *Organization) error {
&TeamUser{OrgID: org.ID},
&TeamUnit{OrgID: org.ID},
&TeamInvite{OrgID: org.ID},
&secret_model.Secret{OwnerID: org.ID},
); err != nil {
return fmt.Errorf("DeleteBeans: %w", err)
}

View File

@ -21,7 +21,6 @@ import (
access_model "code.gitea.io/gitea/models/perm/access"
project_model "code.gitea.io/gitea/models/project"
repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@ -151,7 +150,6 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
&admin_model.Task{RepoID: repoID},
&repo_model.Watch{RepoID: repoID},
&webhook.Webhook{RepoID: repoID},
&secret_model.Secret{RepoID: repoID},
); err != nil {
return fmt.Errorf("deleteBeans: %w", err)
}

View File

@ -1,124 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package secret
import (
"context"
"fmt"
"regexp"
"strings"
"code.gitea.io/gitea/models/db"
secret_module "code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
type ErrSecretInvalidValue struct {
Name *string
Data *string
}
func (err ErrSecretInvalidValue) Error() string {
if err.Name != nil {
return fmt.Sprintf("secret name %q is invalid", *err.Name)
}
if err.Data != nil {
return fmt.Sprintf("secret data %q is invalid", *err.Data)
}
return util.ErrInvalidArgument.Error()
}
func (err ErrSecretInvalidValue) Unwrap() error {
return util.ErrInvalidArgument
}
// Secret represents a secret
type Secret struct {
ID int64
OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"`
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT"` // encrypted data
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
}
// newSecret Creates a new already encrypted secret
func newSecret(ownerID, repoID int64, name, data string) *Secret {
return &Secret{
OwnerID: ownerID,
RepoID: repoID,
Name: strings.ToUpper(name),
Data: data,
}
}
// InsertEncryptedSecret Creates, encrypts, and validates a new secret with yet unencrypted data and insert into database
func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*Secret, error) {
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, strings.TrimSpace(data))
if err != nil {
return nil, err
}
secret := newSecret(ownerID, repoID, name, encrypted)
if err := secret.Validate(); err != nil {
return secret, err
}
return secret, db.Insert(ctx, secret)
}
func init() {
db.RegisterModel(new(Secret))
}
var (
secretNameReg = regexp.MustCompile("^[A-Z_][A-Z0-9_]*$")
forbiddenSecretPrefixReg = regexp.MustCompile("^GIT(EA|HUB)_")
)
// Validate validates the required fields and formats.
func (s *Secret) Validate() error {
switch {
case len(s.Name) == 0 || len(s.Name) > 50:
return ErrSecretInvalidValue{Name: &s.Name}
case len(s.Data) == 0:
return ErrSecretInvalidValue{Data: &s.Data}
case !secretNameReg.MatchString(s.Name) ||
forbiddenSecretPrefixReg.MatchString(s.Name):
return ErrSecretInvalidValue{Name: &s.Name}
default:
return nil
}
}
type FindSecretsOptions struct {
db.ListOptions
OwnerID int64
RepoID int64
}
func (opts *FindSecretsOptions) toConds() builder.Cond {
cond := builder.NewCond()
if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
}
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
return cond
}
func FindSecrets(ctx context.Context, opts FindSecretsOptions) ([]*Secret, error) {
var secrets []*Secret
sess := db.GetEngine(ctx)
if opts.PageSize != 0 {
sess = db.SetSessionPagination(sess, &opts.ListOptions)
}
return secrets, sess.
Where(opts.toConds()).
Find(&secrets)
}

View File

@ -5,10 +5,8 @@ package nuget
import (
"archive/zip"
"bytes"
"encoding/xml"
"errors"
"fmt"
"io"
"path/filepath"
"regexp"
@ -184,23 +182,7 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) {
return &Package{
PackageType: packageType,
ID: p.Metadata.ID,
Version: toNormalizedVersion(v),
Version: v.String(),
Metadata: m,
}, nil
}
// https://learn.microsoft.com/en-us/nuget/concepts/package-versioning#normalized-version-numbers
// https://github.com/NuGet/NuGet.Client/blob/dccbd304b11103e08b97abf4cf4bcc1499d9235a/src/NuGet.Core/NuGet.Versioning/VersionFormatter.cs#L121
func toNormalizedVersion(v *version.Version) string {
var buf bytes.Buffer
segments := v.Segments64()
fmt.Fprintf(&buf, "%d.%d.%d", segments[0], segments[1], segments[2])
if len(segments) > 3 && segments[3] > 0 {
fmt.Fprintf(&buf, ".%d", segments[3])
}
pre := v.Prerelease()
if pre != "" {
fmt.Fprint(&buf, "-", pre)
}
return buf.String()
}

View File

@ -146,19 +146,6 @@ func TestParseNuspecMetaData(t *testing.T) {
assert.Len(t, deps, 1)
assert.Equal(t, dependencyID, deps[0].ID)
assert.Equal(t, dependencyVersion, deps[0].Version)
t.Run("NormalizedVersion", func(t *testing.T) {
np, err := ParseNuspecMetaData(strings.NewReader(`<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>test</id>
<version>1.04.5.2.5-rc.1+metadata</version>
</metadata>
</package>`))
assert.NoError(t, err)
assert.NotNil(t, np)
assert.Equal(t, "1.4.5.2-rc.1", np.Version)
})
})
t.Run("Symbols Package", func(t *testing.T) {

View File

@ -3212,19 +3212,3 @@ owner.settings.cleanuprules.remove.days = Remove versions older than
owner.settings.cleanuprules.remove.pattern = Remove versions matching
owner.settings.cleanuprules.success.update = Cleanup rule has been updated.
owner.settings.cleanuprules.success.delete = Cleanup rule has been deleted.
[secrets]
secrets = Secrets
description = Secrets will be passed to certain actions and cannot be read otherwise.
none = There are no secrets yet.
value = Value
name = Name
creation = Add Secret
creation.name_placeholder = case-insensitive, alphanumeric characters or underscores only, cannot start with GITEA_ or GITHUB_
creation.value_placeholder = Input any content. Whitespace at the start and end will be omitted.
creation.success = The secret '%s' has been added.
creation.failed = Failed to add secret.
deletion = Remove secret
deletion.description = Removing a secret will revoke its access to repositories. Continue?
deletion.success = The secret has been removed.
deletion.failed = Failed to remove secret.

2732
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,24 +13,24 @@
"@citation-js/plugin-software-formats": "0.6.0",
"@claviska/jquery-minicolors": "2.3.6",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "17.10.0",
"@primer/octicons": "17.9.0",
"@vue/compiler-sfc": "3.2.45",
"add-asset-webpack-plugin": "2.0.1",
"css-loader": "6.7.3",
"css-loader": "6.7.2",
"dropzone": "6.0.0-beta.2",
"easymde": "2.18.0",
"esbuild-loader": "2.20.0",
"escape-goat": "4.0.0",
"fast-glob": "3.2.12",
"font-awesome": "4.7.0",
"jquery": "3.6.2",
"jquery": "3.6.1",
"jquery.are-you-sure": "1.9.0",
"katex": "0.16.4",
"katex": "0.16.3",
"less": "4.1.3",
"less-loader": "11.1.0",
"license-checker-webpack-plugin": "0.2.1",
"mermaid": "9.3.0",
"mini-css-extract-plugin": "2.7.2",
"mermaid": "9.2.2",
"mini-css-extract-plugin": "2.7.0",
"monaco-editor": "0.34.1",
"monaco-editor-webpack-plugin": "7.0.1",
"pretty-ms": "8.0.0",
@ -44,31 +44,31 @@
"vue-loader": "17.0.1",
"vue3-calendar-heatmap": "2.0.0",
"webpack": "5.75.0",
"webpack-cli": "5.0.1",
"webpack-cli": "5.0.0",
"workbox-routing": "6.5.4",
"workbox-strategies": "6.5.4",
"worker-loader": "3.0.8",
"wrap-ansi": "8.0.1"
},
"devDependencies": {
"@playwright/test": "1.29.0",
"@playwright/test": "1.28.0",
"@rollup/pluginutils": "5.0.2",
"@stoplight/spectral-cli": "6.6.0",
"eslint": "8.30.0",
"eslint": "8.28.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-sonarjs": "0.17.0",
"eslint-plugin-unicorn": "45.0.2",
"eslint-plugin-vue": "9.8.0",
"eslint-plugin-sonarjs": "0.16.0",
"eslint-plugin-unicorn": "45.0.0",
"eslint-plugin-vue": "9.7.0",
"jsdom": "20.0.3",
"markdownlint-cli": "0.32.2",
"postcss-less": "6.0.0",
"stylelint": "14.16.0",
"stylelint": "14.15.0",
"stylelint-config-standard": "29.0.0",
"stylelint-declaration-strict-value": "1.9.1",
"svgo": "3.0.2",
"updates": "13.2.4",
"vitest": "0.26.1"
"updates": "13.2.1",
"vitest": "0.25.2"
},
"browserslist": [
"defaults",

View File

@ -1 +0,0 @@
<svg viewBox="0 0 16 16" class="svg octicon-goal" width="16" height="16" aria-hidden="true"><g fill-rule="evenodd"><path d="M13.637 2.363 13.302.687a.25.25 0 0 0-.422-.128l-1.374 1.374a.875.875 0 0 0-.256.619v1.137L8.389 6.551A1.502 1.502 0 0 0 6.5 8a1.5 1.5 0 1 0 2.95-.389l2.86-2.861h1.138a.875.875 0 0 0 .619-.256L15.44 3.12a.25.25 0 0 0-.128-.422l-1.676-.335z"/><path d="M2 8a6 6 0 0 1 7.656-5.769.75.75 0 0 0 .413-1.442 7.5 7.5 0 1 0 5.142 5.142.75.75 0 1 0-1.442.413A6 6 0 1 1 2 8z"/><path d="M5 8a3 3 0 0 1 3.346-2.98.75.75 0 1 0 .17-1.49 4.5 4.5 0 1 0 3.953 3.947.75.75 0 1 0-1.49.172A3 3 0 1 1 5 8z"/></g></svg>

Before

Width:  |  Height:  |  Size: 620 B

View File

@ -1 +0,0 @@
<svg viewBox="0 0 16 16" class="svg octicon-read" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M7.115.65a1.75 1.75 0 0 1 1.77 0l6.25 3.663c.536.314.865.889.865 1.51v6.427A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V5.823c0-.621.33-1.196.865-1.51L7.115.65zm1.011 1.293a.25.25 0 0 0-.252 0l-5.72 3.353L6.468 7.76a2.75 2.75 0 0 1 3.066 0l4.312-2.464-5.719-3.353zM14.5 6.65l-3.687 2.106 3.687 2.897V6.65zM5.187 8.756 1.5 6.65v5.003l3.687-2.897zM13.15 12.5H2.85l4.378-3.44a1.25 1.25 0 0 1 1.544 0l4.378 3.44z"/></svg>

Before

Width:  |  Height:  |  Size: 548 B

View File

@ -1 +0,0 @@
<svg viewBox="0 0 16 16" class="svg octicon-rel-file-path" width="16" height="16" aria-hidden="true"><path d="M13.94 3.045a.75.75 0 0 0-1.38-.59l-4.5 10.5a.75.75 0 1 0 1.38.59l4.5-10.5zM5 11.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/></svg>

Before

Width:  |  Height:  |  Size: 238 B

View File

@ -1 +0,0 @@
<svg viewBox="0 0 16 16" class="svg octicon-sponsor-tiers" width="16" height="16" aria-hidden="true"><path d="M10.586 1C12.268 1 13.5 2.37 13.5 4.25c0 1.745-.996 3.359-2.622 4.831-.166.15-.336.297-.509.438l1.116 5.584a.75.75 0 0 1-.991.852l-2.409-.876a.25.25 0 0 0-.17 0l-2.409.876a.75.75 0 0 1-.991-.852L5.63 9.519a13.78 13.78 0 0 1-.51-.438C3.497 7.609 2.5 5.995 2.5 4.25 2.5 2.37 3.732 1 5.414 1c.963 0 1.843.403 2.474 1.073L8 2.198l.112-.125a3.385 3.385 0 0 1 2.283-1.068L10.586 1zm-3.621 9.495-.718 3.594 1.155-.42a1.75 1.75 0 0 1 1.028-.051l.168.051 1.154.42-.718-3.592c-.199.13-.37.235-.505.314l-.169.097a.75.75 0 0 1-.72 0 9.54 9.54 0 0 1-.515-.308l-.16-.105zM10.586 2.5c-.863 0-1.611.58-1.866 1.459-.209.721-1.231.721-1.44 0C7.025 3.08 6.277 2.5 5.414 2.5 4.598 2.5 4 3.165 4 4.25c0 1.23.786 2.504 2.128 3.719.49.443 1.018.846 1.546 1.198l.325.21.076-.047.251-.163a13.341 13.341 0 0 0 1.546-1.198C11.214 6.754 12 5.479 12 4.25c0-1.085-.598-1.75-1.414-1.75z"/></svg>

Before

Width:  |  Height:  |  Size: 974 B

View File

@ -1 +0,0 @@
<svg viewBox="0 0 16 16" class="svg octicon-unlink" width="16" height="16" aria-hidden="true"><path d="M12.914 5.914a2 2 0 0 0-2.828-2.828l-.837.837a.75.75 0 1 1-1.06-1.061l.836-.837a3.5 3.5 0 1 1 4.95 4.95l-.195.194a.75.75 0 0 1-1.06-1.06l.194-.195zm-1.87 3.482a.759.759 0 0 1-.07.079c-.63.63-1.468 1.108-2.343 1.263-.89.159-1.86-.017-2.606-.763a.75.75 0 1 1 1.06-1.06c.329.327.767.438 1.284.347.493-.088 1.018-.36 1.445-.752l-1.247-.897a.709.709 0 0 1-.01-.008l-.295-.212c-.94-.597-1.984-.499-2.676.193l-2.5 2.5a2 2 0 1 0 2.828 2.828l.837-.836a.75.75 0 0 1 1.06 1.06l-.836.837a3.5 3.5 0 0 1-4.95-4.95l2.5-2.5a3.472 3.472 0 0 1 1.354-.848L2.312 3.109a.75.75 0 0 1 .876-1.218l5.93 4.27c.115.074.226.155.335.24l6.235 4.49a.75.75 0 0 1-.876 1.218l-3.768-2.713z"/></svg>

Before

Width:  |  Height:  |  Size: 767 B

View File

@ -1 +0,0 @@
<svg viewBox="0 0 16 16" class="svg octicon-unread" width="16" height="16" aria-hidden="true"><path d="M10.5 3.5H1.75a.25.25 0 0 0-.25.25v.32L8 7.88l3.02-1.77a.75.75 0 0 1 .758 1.295L8.379 9.397a.75.75 0 0 1-.758 0L1.5 5.809v6.441c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4.5a.75.75 0 0 1 1.5 0v4.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25V4.513a.75.75 0 0 1 0-.027V3.75C0 2.784.784 2 1.75 2h8.75a.75.75 0 0 1 0 1.5z"/><path d="M14 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></svg>

Before

Width:  |  Height:  |  Size: 490 B

View File

@ -344,7 +344,7 @@ func createEntry(l *linkBuilder, pd *packages_model.PackageDescriptor, withNames
Content: content,
Properties: &FeedEntryProperties{
Version: pd.Version.Version,
NormalizedVersion: pd.Version.Version,
NormalizedVersion: normalizeVersion(pd.SemVer),
Authors: metadata.Authors,
Dependencies: buildDependencyString(metadata),
Description: metadata.Description,

View File

@ -4,11 +4,15 @@
package nuget
import (
"bytes"
"fmt"
"sort"
"time"
packages_model "code.gitea.io/gitea/models/packages"
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
"github.com/hashicorp/go-version"
)
// https://docs.microsoft.com/en-us/nuget/api/service-index#resources
@ -91,8 +95,8 @@ func createRegistrationIndexResponse(l *linkBuilder, pds []*packages_model.Packa
{
RegistrationPageURL: l.GetRegistrationIndexURL(pds[0].Package.Name),
Count: len(pds),
Lower: pds[0].Version.Version,
Upper: pds[len(pds)-1].Version.Version,
Lower: normalizeVersion(pds[0].SemVer),
Upper: normalizeVersion(pds[len(pds)-1].SemVer),
Items: items,
},
},
@ -169,7 +173,7 @@ type PackageVersionsResponse struct {
func createPackageVersionsResponse(pds []*packages_model.PackageDescriptor) *PackageVersionsResponse {
versions := make([]string, 0, len(pds))
for _, pd := range pds {
versions = append(versions, pd.Version.Version)
versions = append(versions, normalizeVersion(pd.SemVer))
}
return &PackageVersionsResponse{
@ -244,3 +248,15 @@ func createSearchResult(l *linkBuilder, pds []*packages_model.PackageDescriptor)
RegistrationIndexURL: l.GetRegistrationIndexURL(latest.Package.Name),
}
}
// normalizeVersion removes the metadata
func normalizeVersion(v *version.Version) string {
var buf bytes.Buffer
segments := v.Segments64()
fmt.Fprintf(&buf, "%d.%d.%d", segments[0], segments[1], segments[2])
pre := v.Prerelease()
if pre != "" {
fmt.Fprintf(&buf, "-%s", pre)
}
return buf.String()
}

View File

@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/base"
@ -38,8 +37,6 @@ const (
tplSettingsHooks base.TplName = "org/settings/hooks"
// tplSettingsLabels template path for render labels settings
tplSettingsLabels base.TplName = "org/settings/labels"
// tplSettingsSecrets template path for render secrets settings
tplSettingsSecrets base.TplName = "org/settings/secrets"
)
// Settings render the main settings page
@ -249,51 +246,3 @@ func Labels(ctx *context.Context) {
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.HTML(http.StatusOK, tplSettingsLabels)
}
// Secrets render organization secrets page
func Secrets(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.secrets")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsOrgSettingsSecrets"] = true
secrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{OwnerID: ctx.Org.Organization.ID})
if err != nil {
ctx.ServerError("FindSecrets", err)
return
}
ctx.Data["Secrets"] = secrets
ctx.HTML(http.StatusOK, tplSettingsSecrets)
}
// SecretsPost add secrets
func SecretsPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.AddSecretForm)
_, err := secret_model.InsertEncryptedSecret(ctx, ctx.Org.Organization.ID, 0, form.Title, form.Content)
if err != nil {
ctx.Flash.Error(ctx.Tr("secrets.creation.failed"))
log.Error("validate secret: %v", err)
ctx.Redirect(ctx.Org.OrgLink + "/settings/secrets")
return
}
log.Trace("Org %d: secret added", ctx.Org.Organization.ID)
ctx.Flash.Success(ctx.Tr("secrets.creation.success", form.Title))
ctx.Redirect(ctx.Org.OrgLink + "/settings/secrets")
}
// SecretsDelete delete secrets
func SecretsDelete(ctx *context.Context) {
id := ctx.FormInt64("id")
if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil {
ctx.Flash.Error(ctx.Tr("secrets.deletion.failed"))
log.Error("delete secret %d: %v", id, err)
} else {
ctx.Flash.Success(ctx.Tr("secrets.deletion.success"))
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": ctx.Org.OrgLink + "/settings/secrets",
})
}

View File

@ -19,7 +19,6 @@ import (
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
@ -1114,37 +1113,12 @@ func DeployKeys(ctx *context.Context) {
}
ctx.Data["Deploykeys"] = keys
secrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{RepoID: ctx.Repo.Repository.ID})
if err != nil {
ctx.ServerError("FindSecrets", err)
return
}
ctx.Data["Secrets"] = secrets
ctx.HTML(http.StatusOK, tplDeployKeys)
}
// SecretsPost response for creating a new secret
func SecretsPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.AddSecretForm)
_, err := secret_model.InsertEncryptedSecret(ctx, 0, ctx.Repo.Repository.ID, form.Title, form.Content)
if err != nil {
ctx.Flash.Error(ctx.Tr("secrets.creation.failed"))
log.Error("validate secret: %v", err)
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
return
}
log.Trace("Secret added: %d", ctx.Repo.Repository.ID)
ctx.Flash.Success(ctx.Tr("secrets.creation.success", form.Title))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
}
// DeployKeysPost response for adding a deploy key of a repository
func DeployKeysPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.AddKeyForm)
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
ctx.Data["PageIsSettingsKeys"] = true
ctx.Data["DisableSSH"] = setting.SSH.Disabled
@ -1203,20 +1177,6 @@ func DeployKeysPost(ctx *context.Context) {
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
}
func DeleteSecret(ctx *context.Context) {
id := ctx.FormInt64("id")
if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil {
ctx.Flash.Error(ctx.Tr("secrets.deletion.failed"))
log.Error("delete secret %d: %v", id, err)
} else {
ctx.Flash.Success(ctx.Tr("secrets.deletion.success"))
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": ctx.Repo.RepoLink + "/settings/keys",
})
}
// DeleteDeployKey response for deleting a deploy key
func DeleteDeployKey(ctx *context.Context) {
if err := asymkey_service.DeleteDeployKey(ctx.Doer, ctx.FormInt64("id")); err != nil {

View File

@ -272,7 +272,7 @@ func getFileReader(repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileIn
}
meta, err := git_model.GetLFSMetaObjectByOid(repoID, pointer.Oid)
if err != nil && err != git_model.ErrLFSObjectNotExist { // fallback to plain file
if err != git_model.ErrLFSObjectNotExist { // fallback to plain file
return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil
}

View File

@ -774,12 +774,6 @@ func RegisterRoutes(m *web.Route) {
m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), org.InitializeLabels)
})
m.Group("/secrets", func() {
m.Get("", org.Secrets)
m.Post("", web.Bind(forms.AddSecretForm{}), org.SecretsPost)
m.Post("/delete", org.SecretsDelete)
})
m.Route("/delete", "GET,POST", org.SettingsDelete)
m.Group("/packages", func() {
@ -918,10 +912,6 @@ func RegisterRoutes(m *web.Route) {
m.Combo("").Get(repo.DeployKeys).
Post(web.Bind(forms.AddKeyForm{}), repo.DeployKeysPost)
m.Post("/delete", repo.DeleteDeployKey)
m.Group("/secrets", func() {
m.Post("", web.Bind(forms.AddSecretForm{}), repo.SecretsPost)
m.Post("/delete", repo.DeleteSecret)
})
})
m.Group("/lfs", func() {

View File

@ -363,18 +363,6 @@ func (f *AddKeyForm) Validate(req *http.Request, errs binding.Errors) binding.Er
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
}
// AddSecretForm for adding secrets
type AddSecretForm struct {
Title string `binding:"Required;MaxSize(50)"`
Content string `binding:"Required"`
}
// Validate validates the fields
func (f *AddSecretForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
ctx := context.GetContext(req)
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
}
// NewAccessTokenForm form for creating access token
type NewAccessTokenForm struct {
Name string `binding:"Required;MaxSize(255)"`

View File

@ -12,9 +12,6 @@
<a class="{{if .PageIsOrgSettingsLabels}}active {{end}}item" href="{{.OrgLink}}/settings/labels">
{{.locale.Tr "repo.labels"}}
</a>
<a class="{{if .PageIsOrgSettingsSecrets}}active {{end}}item" href="{{.OrgLink}}/settings/secrets">
{{.locale.Tr "secrets.secrets"}}
</a>
{{if .EnableOAuth2}}
<a class="{{if .PageIsSettingsApplications}}active {{end}}item" href="{{.OrgLink}}/settings/applications">
{{.locale.Tr "settings.applications"}}

View File

@ -1,83 +0,0 @@
{{template "base/head" .}}
<div class="page-content organization settings webhooks">
{{template "org/header" .}}
<div class="ui container">
<div class="ui grid">
{{template "org/settings/navbar" .}}
<div class="ui twelve wide column content">
{{template "base/alert" .}}
<h4 class="ui top attached header">
{{.locale.Tr "secrets.secrets"}}
<div class="ui right">
<div class="ui primary tiny show-panel button" data-panel="#add-secret-panel">{{.locale.Tr "secrets.creation"}}</div>
</div>
</h4>
<div class="ui attached segment">
<div class="{{if not .HasError}}hide {{end}}mb-4" id="add-secret-panel">
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<div class="field">
{{.locale.Tr "secrets.description"}}
</div>
<div class="field{{if .Err_Title}} error{{end}}">
<label for="secret-title">{{.locale.Tr "secrets.name"}}</label>
<input id="secret-title" name="title" value="{{.title}}" autofocus required pattern="^[a-zA-Z_][a-zA-Z0-9_]*$" placeholder="{{.locale.Tr "secrets.creation.name_placeholder"}}">
</div>
<div class="field{{if .Err_Content}} error{{end}}">
<label for="secret-content">{{.locale.Tr "secrets.value"}}</label>
<textarea id="secret-content" name="content" required placeholder="{{.locale.Tr "secrets.creation.value_placeholder"}}">{{.content}}</textarea>
</div>
<button class="ui green button">
{{.locale.Tr "secrets.creation"}}
</button>
<button class="ui hide-panel button" data-panel="#add-secret-panel">
{{.locale.Tr "cancel"}}
</button>
</form>
</div>
{{if .Secrets}}
<div class="ui key list">
{{range .Secrets}}
<div class="item">
<div class="right floated content">
<button class="ui red tiny button delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
{{$.locale.Tr "settings.delete_key"}}
</button>
</div>
<div class="left floated content">
<i>{{svg "octicon-key" 32}}</i>
</div>
<div class="content">
<strong>{{.Name}}</strong>
<div class="print meta">******</div>
<div class="activity meta">
<i>
{{$.locale.Tr "settings.add_on"}}
<span>{{.CreatedUnix.FormatShort}}</span>
</i>
</div>
</div>
</div>
{{end}}
</div>
{{else}}
{{.locale.Tr "secrets.none"}}
{{end}}
</div>
</div>
</div>
</div>
</div>
<div class="ui small basic delete modal">
<div class="ui header">
{{svg "octicon-trash" 16 "mr-2"}}
{{.locale.Tr "secrets.deletion"}}
</div>
<div class="content">
<p>{{.locale.Tr "secrets.deletion.description"}}</p>
</div>
{{template "base/delete_modal_actions" .}}
</div>
{{template "base/footer" .}}

View File

@ -51,7 +51,7 @@
{{range .Deploykeys}}
<div class="item">
<div class="right floated content">
<button class="ui red tiny button delete-button" data-modal-id="delete-deploy_keys-modal" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
<button class="ui red tiny button delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
{{$.locale.Tr "settings.delete_key"}}
</button>
</div>
@ -75,11 +75,9 @@
{{end}}
</div>
</div>
<br/>
{{template "repo/settings/secrets" .}}
</div>
<div class="ui small basic delete modal" id="delete-deploy_keys-modal">
<div class="ui small basic delete modal">
<div class="ui icon header">
{{svg "octicon-trash"}}
{{.locale.Tr "repo.settings.deploy_key_deletion"}}

View File

@ -12,7 +12,7 @@
{{if or .SignedUser.AllowGitHook .SignedUser.IsAdmin}}
<li {{if .PageIsSettingsGitHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks/git">{{.locale.Tr "repo.settings.githooks"}}</a></li>
{{end}}
<li {{if .PageIsSettingsKeys}}class="current"{{end}}><a href="{{.RepoLink}}/settings/keys">{{.locale.Tr "secrets.secrets"}}</a></li>
<li {{if .PageIsSettingsKeys}}class="current"{{end}}><a href="{{.RepoLink}}/settings/keys">{{.locale.Tr "repo.settings.deploy_keys"}}</a></li>
</ul>
</div>
</div>

View File

@ -25,7 +25,7 @@
</a>
{{end}}
<a class="{{if .PageIsSettingsKeys}}active {{end}}item" href="{{.RepoLink}}/settings/keys">
{{.locale.Tr "secrets.secrets"}}
{{.locale.Tr "repo.settings.deploy_keys"}}
</a>
{{if .LFSStartServer}}
<a class="{{if .PageIsSettingsLFS}}active {{end}}item" href="{{.RepoLink}}/settings/lfs">

View File

@ -1,80 +0,0 @@
<div class="ui container">
<h4 class="ui top attached header">
{{.locale.Tr "secrets.secrets"}}
<div class="ui right">
<div class="ui primary tiny show-panel button" data-panel="#add-secret-panel">{{.locale.Tr "secrets.creation"}}</div>
</div>
</h4>
<div class="ui attached segment">
<div class="{{if not .HasError}}hide {{end}}mb-4" id="add-secret-panel">
<form class="ui form" action="{{.Link}}/secrets" method="post">
{{.CsrfTokenHtml}}
<div class="field">
{{.locale.Tr "secrets.description"}}
</div>
<div class="field{{if .Err_Title}} error{{end}}">
<label for="secret-title">{{.locale.Tr "secrets.name"}}</label>
<input id="secret-title" name="title" value="{{.title}}" autofocus required pattern="^[a-zA-Z_][a-zA-Z0-9_]*$" placeholder="{{.locale.Tr "secrets.creation.name_placeholder"}}">
</div>
<div class="field{{if .Err_Content}} error{{end}}">
<label for="secret-content">{{.locale.Tr "secrets.value"}}</label>
<textarea id="secret-content" name="content" required placeholder="{{.locale.Tr "secrets.creation.value_placeholder"}}">{{.content}}</textarea>
</div>
<button class="ui green button">
{{.locale.Tr "secrets.creation"}}
</button>
<button class="ui hide-panel button" data-panel="#add-secret-panel">
{{.locale.Tr "cancel"}}
</button>
</form>
</div>
{{if .Secrets}}
<div class="ui key list">
{{range .Secrets}}
<div class="item">
<div class="right floated content">
<button class="ui red tiny button delete-button" data-modal-id="delete-secret-modal" data-url="{{$.Link}}/secrets/delete" data-id="{{.ID}}">
{{$.locale.Tr "settings.delete_key"}}
</button>
</div>
<div class="left floated content">
<i>{{svg "octicon-key" 32}}</i>
</div>
<div class="content">
<strong>{{.Name}}</strong>
<div class="print meta">******</div>
<div class="activity meta">
<i>
{{$.locale.Tr "settings.add_on"}}
<span>{{.CreatedUnix.FormatShort}}</span>
</i>
</div>
</div>
</div>
{{end}}
</div>
{{else}}
{{.locale.Tr "secrets.none"}}
{{end}}
</div>
</div>
<div class="ui small basic delete modal" id="delete-secret-modal">
<div class="ui icon header">
{{svg "octicon-trash"}}
{{.locale.Tr "secrets.deletion"}}
</div>
<div class="content">
<p>{{.locale.Tr "secrets.deletion.description"}}</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i>
{{.locale.Tr "modal.no"}}
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i>
{{.locale.Tr "modal.yes"}}
</div>
</div>
</div>

View File

@ -24,7 +24,7 @@ import (
func TestAPITeam(t *testing.T) {
defer tests.PrepareTestEnv(t)()
teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 1})
teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{})
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID})
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID})

View File

@ -264,45 +264,18 @@ var tokenCounter int64
func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
t.Helper()
var token string
req := NewRequest(t, "GET", "/user/settings/applications")
resp := session.MakeRequest(t, req, http.StatusOK)
var csrf string
for _, cookie := range resp.Result().Cookies() {
if cookie.Name != "_csrf" {
continue
}
csrf = cookie.Value
break
}
if csrf == "" {
doc := NewHTMLParser(t, resp.Body)
csrf = doc.GetCSRF()
}
assert.NotEmpty(t, csrf)
req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
"_csrf": csrf,
"_csrf": doc.GetCSRF(),
"name": fmt.Sprintf("api-testing-token-%d", atomic.AddInt64(&tokenCounter, 1)),
})
resp = session.MakeRequest(t, req, http.StatusSeeOther)
// Log the flash values on failure
if !assert.Equal(t, resp.Result().Header["Location"], []string{"/user/settings/applications"}) {
for _, cookie := range resp.Result().Cookies() {
if cookie.Name != "macaron_flash" {
continue
}
flash, _ := url.ParseQuery(cookie.Value)
for key, value := range flash {
t.Logf("Flash %q: %q", key, value)
}
}
}
session.MakeRequest(t, req, http.StatusSeeOther)
req = NewRequest(t, "GET", "/user/settings/applications")
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
token = htmlDoc.doc.Find(".ui.info p").Text()
token := htmlDoc.doc.Find(".ui.info p").Text()
assert.NotEmpty(t, token)
return token
}

View File

@ -1,7 +1,7 @@
import {defineConfig} from 'vitest/dist/config.js';
import {readFile} from 'node:fs/promises';
import {readFile} from 'fs/promises';
import {dataToEsm} from '@rollup/pluginutils';
import {extname} from 'node:path';
import {extname} from 'path';
function stringPlugin() {
return {

View File

@ -49,8 +49,6 @@ async function initRepoProjectSortable() {
filter: '[data-id="0"]',
animation: 150,
ghostClass: 'card-ghost',
delayOnTouchOnly: true,
delay: 500,
onSort: () => {
boardColumns = mainBoard.getElementsByClassName('board-column');
for (let i = 0; i < boardColumns.length; i++) {
@ -78,8 +76,6 @@ async function initRepoProjectSortable() {
ghostClass: 'card-ghost',
onAdd: moveIssue,
onUpdate: moveIssue,
delayOnTouchOnly: true,
delay: 500,
});
}
}

View File

@ -6,10 +6,10 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
import {VueLoaderPlugin} from 'vue-loader';
import EsBuildLoader from 'esbuild-loader';
import {parse, dirname} from 'node:path';
import {parse, dirname} from 'path';
import webpack from 'webpack';
import {fileURLToPath} from 'node:url';
import {readFileSync} from 'node:fs';
import {fileURLToPath} from 'url';
import {readFileSync} from 'fs';
const {ESBuildMinifyPlugin} = EsBuildLoader;
const {SourceMapDevToolPlugin} = webpack;