2014-03-16 13:24:13 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2019-06-16 10:50:46 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2014-03-16 13:24:13 +04:00
2021-12-10 11:14:24 +03:00
package asymkey
2014-02-17 19:57:23 +04:00
import (
2021-12-10 11:14:24 +03:00
"context"
2014-02-17 19:57:23 +04:00
"fmt"
2014-03-16 13:24:13 +04:00
"strings"
2014-02-17 19:57:23 +04:00
"time"
2014-03-03 00:25:09 +04:00
2022-01-02 16:12:35 +03:00
"code.gitea.io/gitea/models/auth"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2021-11-28 14:58:28 +03:00
"code.gitea.io/gitea/models/perm"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/log"
2019-08-15 17:46:21 +03:00
"code.gitea.io/gitea/modules/timeutil"
2020-08-11 23:05:34 +03:00
"code.gitea.io/gitea/modules/util"
2014-02-17 19:57:23 +04:00
2021-11-17 15:34:35 +03:00
"golang.org/x/crypto/ssh"
2021-07-24 13:16:34 +03:00
"xorm.io/builder"
2014-03-17 22:03:58 +04:00
)
2016-11-26 03:36:03 +03:00
// KeyType specifies the key type
2015-08-06 17:48:11 +03:00
type KeyType int
const (
2016-11-26 03:36:03 +03:00
// KeyTypeUser specifies the user key
2016-11-07 19:53:22 +03:00
KeyTypeUser = iota + 1
2016-11-26 03:36:03 +03:00
// KeyTypeDeploy specifies the deploy key
2016-11-07 19:53:22 +03:00
KeyTypeDeploy
2020-10-11 03:38:09 +03:00
// KeyTypePrincipal specifies the authorized principal key
KeyTypePrincipal
2015-08-06 17:48:11 +03:00
)
2016-07-26 05:47:25 +03:00
// PublicKey represents a user or deploy SSH public key.
2014-02-17 19:57:23 +04:00
type PublicKey struct {
2021-11-28 14:58:28 +03:00
ID int64 ` xorm:"pk autoincr" `
OwnerID int64 ` xorm:"INDEX NOT NULL" `
Name string ` xorm:"NOT NULL" `
Fingerprint string ` xorm:"INDEX NOT NULL" `
2022-08-22 16:32:28 +03:00
Content string ` xorm:"MEDIUMTEXT NOT NULL" `
2021-11-28 14:58:28 +03:00
Mode perm . AccessMode ` xorm:"NOT NULL DEFAULT 2" `
Type KeyType ` xorm:"NOT NULL DEFAULT 1" `
LoginSourceID int64 ` xorm:"NOT NULL DEFAULT 0" `
2016-03-10 03:53:30 +03:00
2019-08-15 17:46:21 +03:00
CreatedUnix timeutil . TimeStamp ` xorm:"created" `
UpdatedUnix timeutil . TimeStamp ` xorm:"updated" `
HasRecentActivity bool ` xorm:"-" `
HasUsed bool ` xorm:"-" `
2021-12-19 08:37:18 +03:00
Verified bool ` xorm:"NOT NULL DEFAULT false" `
2015-08-06 17:48:11 +03:00
}
2021-09-19 14:49:59 +03:00
func init ( ) {
db . RegisterModel ( new ( PublicKey ) )
}
2017-10-01 19:52:35 +03:00
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func ( key * PublicKey ) AfterLoad ( ) {
2017-12-11 07:37:04 +03:00
key . HasUsed = key . UpdatedUnix > key . CreatedUnix
2019-08-15 17:46:21 +03:00
key . HasRecentActivity = key . UpdatedUnix . AddDuration ( 7 * 24 * time . Hour ) > timeutil . TimeStampNow ( )
2014-02-17 19:57:23 +04:00
}
2016-07-26 05:47:25 +03:00
// OmitEmail returns content of public key without email address.
2016-11-26 03:36:03 +03:00
func ( key * PublicKey ) OmitEmail ( ) string {
return strings . Join ( strings . Split ( key . Content , " " ) [ : 2 ] , " " )
2014-11-23 10:33:47 +03:00
}
2016-07-26 05:47:25 +03:00
// AuthorizedString returns formatted public key string for authorized_keys file.
2021-07-24 13:16:34 +03:00
//
// TODO: Consider dropping this function
2016-07-26 05:47:25 +03:00
func ( key * PublicKey ) AuthorizedString ( ) string {
2021-07-24 13:16:34 +03:00
return AuthorizedStringForKey ( key )
2019-06-16 10:50:46 +03:00
}
2022-05-20 17:08:52 +03:00
func addKey ( ctx context . Context , key * PublicKey ) ( err error ) {
2018-10-21 00:25:14 +03:00
if len ( key . Fingerprint ) == 0 {
2022-06-04 22:18:50 +03:00
key . Fingerprint , err = CalcFingerprint ( key . Content )
2017-02-14 09:12:52 +03:00
if err != nil {
return err
}
2014-03-16 14:16:03 +04:00
}
// Save SSH key.
2022-05-20 17:08:52 +03:00
if err = db . Insert ( ctx , key ) ; err != nil {
2014-03-16 14:16:03 +04:00
return err
2015-08-06 17:48:11 +03:00
}
2015-12-11 13:02:33 +03:00
2016-07-26 05:47:25 +03:00
return appendAuthorizedKeysToFile ( key )
2015-08-06 17:48:11 +03:00
}
// AddPublicKey adds new public key to database and authorized_keys file.
2023-10-11 07:24:07 +03:00
func AddPublicKey ( ctx context . Context , ownerID int64 , name , content string , authSourceID int64 ) ( * PublicKey , error ) {
2016-02-17 01:01:56 +03:00
log . Trace ( content )
2017-02-14 09:12:52 +03:00
2022-06-04 22:18:50 +03:00
fingerprint , err := CalcFingerprint ( content )
2017-02-14 09:12:52 +03:00
if err != nil {
return nil , err
}
2023-10-11 07:24:07 +03:00
ctx , committer , err := db . TxContext ( ctx )
2021-11-21 18:41:00 +03:00
if err != nil {
2019-02-04 02:56:53 +03:00
return nil , err
}
2021-11-21 18:41:00 +03:00
defer committer . Close ( )
2019-02-04 02:56:53 +03:00
2022-05-20 17:08:52 +03:00
if err := checkKeyFingerprint ( ctx , fingerprint ) ; err != nil {
2015-12-03 08:24:37 +03:00
return nil , err
2014-02-17 19:57:23 +04:00
}
2015-08-06 17:48:11 +03:00
// Key name of same user cannot be duplicated.
2022-05-20 17:08:52 +03:00
has , err := db . GetEngine ( ctx ) .
2016-11-10 18:16:32 +03:00
Where ( "owner_id = ? AND name = ?" , ownerID , name ) .
Get ( new ( PublicKey ) )
2015-08-06 17:48:11 +03:00
if err != nil {
2015-12-03 08:24:37 +03:00
return nil , err
2015-08-06 17:48:11 +03:00
} else if has {
2015-12-03 08:24:37 +03:00
return nil , ErrKeyNameAlreadyUsed { ownerID , name }
2015-08-06 17:48:11 +03:00
}
key := & PublicKey {
2018-05-24 07:59:02 +03:00
OwnerID : ownerID ,
Name : name ,
Fingerprint : fingerprint ,
Content : content ,
2021-11-28 14:58:28 +03:00
Mode : perm . AccessModeWrite ,
2018-05-24 07:59:02 +03:00
Type : KeyTypeUser ,
2022-01-02 16:12:35 +03:00
LoginSourceID : authSourceID ,
2015-08-06 17:48:11 +03:00
}
2022-05-20 17:08:52 +03:00
if err = addKey ( ctx , key ) ; err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "addKey: %w" , err )
2015-08-06 17:48:11 +03:00
}
2021-11-21 18:41:00 +03:00
return key , committer . Commit ( )
2014-02-17 19:57:23 +04:00
}
2015-08-06 17:48:11 +03:00
// GetPublicKeyByID returns public key by given ID.
2023-10-11 07:24:07 +03:00
func GetPublicKeyByID ( ctx context . Context , keyID int64 ) ( * PublicKey , error ) {
2014-08-10 02:40:10 +04:00
key := new ( PublicKey )
2023-10-11 07:24:07 +03:00
has , err := db . GetEngine ( ctx ) .
2020-03-22 18:12:55 +03:00
ID ( keyID ) .
2016-11-10 18:16:32 +03:00
Get ( key )
2014-08-10 02:40:10 +04:00
if err != nil {
return nil , err
} else if ! has {
2015-08-06 17:48:11 +03:00
return nil , ErrKeyNotExist { keyID }
2014-08-10 02:40:10 +04:00
}
return key , nil
}
2022-05-20 17:08:52 +03:00
// SearchPublicKeyByContent searches content as prefix (leak e-mail part)
// and returns public key found.
func SearchPublicKeyByContent ( ctx context . Context , content string ) ( * PublicKey , error ) {
2015-11-09 00:59:56 +03:00
key := new ( PublicKey )
2022-05-20 17:08:52 +03:00
has , err := db . GetEngine ( ctx ) .
2016-11-10 18:16:32 +03:00
Where ( "content like ?" , content + "%" ) .
Get ( key )
2015-11-09 00:59:56 +03:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrKeyNotExist { }
}
return key , nil
}
2022-05-20 17:08:52 +03:00
// SearchPublicKeyByContentExact searches content
2018-12-27 20:28:48 +03:00
// and returns public key found.
2022-05-20 17:08:52 +03:00
func SearchPublicKeyByContentExact ( ctx context . Context , content string ) ( * PublicKey , error ) {
2020-10-11 03:38:09 +03:00
key := new ( PublicKey )
2022-05-20 17:08:52 +03:00
has , err := db . GetEngine ( ctx ) .
2020-10-11 03:38:09 +03:00
Where ( "content = ?" , content ) .
Get ( key )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrKeyNotExist { }
}
return key , nil
}
2023-11-24 06:49:41 +03:00
type FindPublicKeyOptions struct {
db . ListOptions
OwnerID int64
Fingerprint string
KeyTypes [ ] KeyType
NotKeytype KeyType
LoginSourceID int64
}
func ( opts FindPublicKeyOptions ) ToConds ( ) builder . Cond {
2018-11-01 06:40:49 +03:00
cond := builder . NewCond ( )
2023-11-24 06:49:41 +03:00
if opts . OwnerID > 0 {
cond = cond . And ( builder . Eq { "owner_id" : opts . OwnerID } )
2018-11-01 06:40:49 +03:00
}
2023-11-24 06:49:41 +03:00
if opts . Fingerprint != "" {
cond = cond . And ( builder . Eq { "fingerprint" : opts . Fingerprint } )
2018-11-01 06:40:49 +03:00
}
2023-11-24 06:49:41 +03:00
if len ( opts . KeyTypes ) > 0 {
2024-01-15 05:19:25 +03:00
cond = cond . And ( builder . In ( "`type`" , opts . KeyTypes ) )
2020-01-24 22:00:29 +03:00
}
2023-11-24 06:49:41 +03:00
if opts . NotKeytype > 0 {
2024-01-15 05:19:25 +03:00
cond = cond . And ( builder . Neq { "`type`" : opts . NotKeytype } )
2023-11-24 06:49:41 +03:00
}
if opts . LoginSourceID > 0 {
cond = cond . And ( builder . Eq { "login_source_id" : opts . LoginSourceID } )
}
return cond
2018-05-24 07:59:02 +03:00
}
2017-04-08 03:40:38 +03:00
// UpdatePublicKeyUpdated updates public key use time.
2023-10-11 07:24:07 +03:00
func UpdatePublicKeyUpdated ( ctx context . Context , id int64 ) error {
2017-07-20 06:15:10 +03:00
// Check if key exists before update as affected rows count is unreliable
// and will return 0 affected rows if two updates are made at the same time
2023-10-11 07:24:07 +03:00
if cnt , err := db . GetEngine ( ctx ) . ID ( id ) . Count ( & PublicKey { } ) ; err != nil {
2017-07-20 06:15:10 +03:00
return err
} else if cnt != 1 {
return ErrKeyNotExist { id }
}
2023-10-11 07:24:07 +03:00
_ , err := db . GetEngine ( ctx ) . ID ( id ) . Cols ( "updated_unix" ) . Update ( & PublicKey {
2019-08-15 17:46:21 +03:00
UpdatedUnix : timeutil . TimeStampNow ( ) ,
2017-04-08 03:40:38 +03:00
} )
if err != nil {
return err
}
return nil
}
2020-12-26 07:24:47 +03:00
// PublicKeysAreExternallyManaged returns whether the provided KeyID represents an externally managed Key
2023-10-11 07:24:07 +03:00
func PublicKeysAreExternallyManaged ( ctx context . Context , keys [ ] * PublicKey ) ( [ ] bool , error ) {
2024-08-15 18:59:01 +03:00
sourceCache := make ( map [ int64 ] * auth . Source , len ( keys ) )
2020-12-26 07:24:47 +03:00
externals := make ( [ ] bool , len ( keys ) )
2024-08-15 18:59:01 +03:00
2020-12-26 07:24:47 +03:00
for i , key := range keys {
if key . LoginSourceID == 0 {
externals [ i ] = false
2024-08-15 18:59:01 +03:00
continue
2020-12-26 07:24:47 +03:00
}
2024-08-15 18:59:01 +03:00
source , ok := sourceCache [ key . LoginSourceID ]
if ! ok {
2020-12-26 07:24:47 +03:00
var err error
2023-10-11 07:24:07 +03:00
source , err = auth . GetSourceByID ( ctx , key . LoginSourceID )
2020-12-26 07:24:47 +03:00
if err != nil {
2022-01-02 16:12:35 +03:00
if auth . IsErrSourceNotExist ( err ) {
2020-12-26 07:24:47 +03:00
externals [ i ] = false
2024-08-15 18:59:01 +03:00
sourceCache [ key . LoginSourceID ] = & auth . Source {
2020-12-26 07:24:47 +03:00
ID : key . LoginSourceID ,
}
2024-08-15 18:59:01 +03:00
continue
2020-12-26 07:24:47 +03:00
}
return nil , err
}
}
2022-01-02 16:12:35 +03:00
if sshKeyProvider , ok := source . Cfg . ( auth . SSHKeyProvider ) ; ok && sshKeyProvider . ProvidesSSHKeys ( ) {
2020-12-26 07:24:47 +03:00
// Disable setting SSH keys for this user
externals [ i ] = true
}
}
return externals , nil
}
// PublicKeyIsExternallyManaged returns whether the provided KeyID represents an externally managed Key
2023-10-11 07:24:07 +03:00
func PublicKeyIsExternallyManaged ( ctx context . Context , id int64 ) ( bool , error ) {
key , err := GetPublicKeyByID ( ctx , id )
2020-12-26 07:24:47 +03:00
if err != nil {
return false , err
}
if key . LoginSourceID == 0 {
return false , nil
}
2023-10-11 07:24:07 +03:00
source , err := auth . GetSourceByID ( ctx , key . LoginSourceID )
2020-12-26 07:24:47 +03:00
if err != nil {
2022-01-02 16:12:35 +03:00
if auth . IsErrSourceNotExist ( err ) {
2020-12-26 07:24:47 +03:00
return false , nil
}
return false , err
}
2022-01-02 16:12:35 +03:00
if sshKeyProvider , ok := source . Cfg . ( auth . SSHKeyProvider ) ; ok && sshKeyProvider . ProvidesSSHKeys ( ) {
2020-12-26 07:24:47 +03:00
// Disable setting SSH keys for this user
return true , nil
}
return false , nil
}
2021-07-24 13:16:34 +03:00
// deleteKeysMarkedForDeletion returns true if ssh keys needs update
2023-10-11 07:24:07 +03:00
func deleteKeysMarkedForDeletion ( ctx context . Context , keys [ ] string ) ( bool , error ) {
2021-07-24 13:16:34 +03:00
// Start session
2023-10-11 07:24:07 +03:00
ctx , committer , err := db . TxContext ( ctx )
2021-11-21 18:41:00 +03:00
if err != nil {
2021-07-24 13:16:34 +03:00
return false , err
2015-12-03 08:24:37 +03:00
}
2021-11-21 18:41:00 +03:00
defer committer . Close ( )
2015-12-03 08:24:37 +03:00
2021-07-24 13:16:34 +03:00
// Delete keys marked for deletion
var sshKeysNeedUpdate bool
for _ , KeyToDelete := range keys {
2022-05-20 17:08:52 +03:00
key , err := SearchPublicKeyByContent ( ctx , KeyToDelete )
2015-12-06 01:13:13 +03:00
if err != nil {
2021-07-24 13:16:34 +03:00
log . Error ( "SearchPublicKeyByContent: %v" , err )
continue
2015-08-06 17:48:11 +03:00
}
2023-12-25 23:25:29 +03:00
if _ , err = db . DeleteByID [ PublicKey ] ( ctx , key . ID ) ; err != nil {
log . Error ( "DeleteByID[PublicKey]: %v" , err )
2021-07-24 13:16:34 +03:00
continue
2019-01-09 21:10:46 +03:00
}
2021-07-24 13:16:34 +03:00
sshKeysNeedUpdate = true
2015-08-06 17:48:11 +03:00
}
2021-11-21 18:41:00 +03:00
if err := committer . Commit ( ) ; err != nil {
2021-07-24 13:16:34 +03:00
return false , err
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
return sshKeysNeedUpdate , nil
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
// AddPublicKeysBySource add a users public keys. Returns true if there are changes.
2023-10-11 07:24:07 +03:00
func AddPublicKeysBySource ( ctx context . Context , usr * user_model . User , s * auth . Source , sshPublicKeys [ ] string ) bool {
2021-07-24 13:16:34 +03:00
var sshKeysNeedUpdate bool
for _ , sshKey := range sshPublicKeys {
var err error
found := false
keys := [ ] byte ( sshKey )
loop :
for len ( keys ) > 0 && err == nil {
var out ssh . PublicKey
// We ignore options as they are not relevant to Gitea
out , _ , _ , keys , err = ssh . ParseAuthorizedKey ( keys )
2020-10-11 03:38:09 +03:00
if err != nil {
2021-07-24 13:16:34 +03:00
break loop
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
found = true
marshalled := string ( ssh . MarshalAuthorizedKey ( out ) )
marshalled = marshalled [ : len ( marshalled ) - 1 ]
sshKeyName := fmt . Sprintf ( "%s-%s" , s . Name , ssh . FingerprintSHA256 ( out ) )
2023-10-11 07:24:07 +03:00
if _ , err := AddPublicKey ( ctx , usr . ID , sshKeyName , marshalled , s . ID ) ; err != nil {
2021-07-24 13:16:34 +03:00
if IsErrKeyAlreadyExist ( err ) {
log . Trace ( "AddPublicKeysBySource[%s]: Public SSH Key %s already exists for user" , sshKeyName , usr . Name )
} else {
log . Error ( "AddPublicKeysBySource[%s]: Error adding Public SSH Key for user %s: %v" , sshKeyName , usr . Name , err )
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
} else {
log . Trace ( "AddPublicKeysBySource[%s]: Added Public SSH Key for user %s" , sshKeyName , usr . Name )
sshKeysNeedUpdate = true
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
}
if ! found && err != nil {
log . Warn ( "AddPublicKeysBySource[%s]: Skipping invalid Public SSH Key for user %s: %v" , s . Name , usr . Name , sshKey )
2020-10-11 03:38:09 +03:00
}
}
2021-07-24 13:16:34 +03:00
return sshKeysNeedUpdate
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
// SynchronizePublicKeys updates a users public keys. Returns true if there are changes.
2023-10-11 07:24:07 +03:00
func SynchronizePublicKeys ( ctx context . Context , usr * user_model . User , s * auth . Source , sshPublicKeys [ ] string ) bool {
2021-07-24 13:16:34 +03:00
var sshKeysNeedUpdate bool
2020-10-11 03:38:09 +03:00
2021-07-24 13:16:34 +03:00
log . Trace ( "synchronizePublicKeys[%s]: Handling Public SSH Key synchronization for user %s" , s . Name , usr . Name )
2020-10-11 03:38:09 +03:00
2021-07-24 13:16:34 +03:00
// Get Public Keys from DB with current LDAP source
var giteaKeys [ ] string
2023-11-24 06:49:41 +03:00
keys , err := db . Find [ PublicKey ] ( ctx , FindPublicKeyOptions {
OwnerID : usr . ID ,
LoginSourceID : s . ID ,
} )
2021-07-24 13:16:34 +03:00
if err != nil {
log . Error ( "synchronizePublicKeys[%s]: Error listing Public SSH Keys for user %s: %v" , s . Name , usr . Name , err )
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
for _ , v := range keys {
giteaKeys = append ( giteaKeys , v . OmitEmail ( ) )
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
// Process the provided keys to remove duplicates and name part
var providedKeys [ ] string
for _ , v := range sshPublicKeys {
sshKeySplit := strings . Split ( v , " " )
if len ( sshKeySplit ) > 1 {
key := strings . Join ( sshKeySplit [ : 2 ] , " " )
Improve utils of slices (#22379)
- Move the file `compare.go` and `slice.go` to `slice.go`.
- Fix `ExistsInSlice`, it's buggy
- It uses `sort.Search`, so it assumes that the input slice is sorted.
- It passes `func(i int) bool { return slice[i] == target })` to
`sort.Search`, that's incorrect, check the doc of `sort.Search`.
- Conbine `IsInt64InSlice(int64, []int64)` and `ExistsInSlice(string,
[]string)` to `SliceContains[T]([]T, T)`.
- Conbine `IsSliceInt64Eq([]int64, []int64)` and `IsEqualSlice([]string,
[]string)` to `SliceSortedEqual[T]([]T, T)`.
- Add `SliceEqual[T]([]T, T)` as a distinction from
`SliceSortedEqual[T]([]T, T)`.
- Redesign `RemoveIDFromList([]int64, int64) ([]int64, bool)` to
`SliceRemoveAll[T]([]T, T) []T`.
- Add `SliceContainsFunc[T]([]T, func(T) bool)` and
`SliceRemoveAllFunc[T]([]T, func(T) bool)` for general use.
- Add comments to explain why not `golang.org/x/exp/slices`.
- Add unit tests.
2023-01-11 08:31:16 +03:00
if ! util . SliceContainsString ( providedKeys , key ) {
2021-07-24 13:16:34 +03:00
providedKeys = append ( providedKeys , key )
2020-11-28 05:42:08 +03:00
}
}
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
// Check if Public Key sync is needed
Improve utils of slices (#22379)
- Move the file `compare.go` and `slice.go` to `slice.go`.
- Fix `ExistsInSlice`, it's buggy
- It uses `sort.Search`, so it assumes that the input slice is sorted.
- It passes `func(i int) bool { return slice[i] == target })` to
`sort.Search`, that's incorrect, check the doc of `sort.Search`.
- Conbine `IsInt64InSlice(int64, []int64)` and `ExistsInSlice(string,
[]string)` to `SliceContains[T]([]T, T)`.
- Conbine `IsSliceInt64Eq([]int64, []int64)` and `IsEqualSlice([]string,
[]string)` to `SliceSortedEqual[T]([]T, T)`.
- Add `SliceEqual[T]([]T, T)` as a distinction from
`SliceSortedEqual[T]([]T, T)`.
- Redesign `RemoveIDFromList([]int64, int64) ([]int64, bool)` to
`SliceRemoveAll[T]([]T, T) []T`.
- Add `SliceContainsFunc[T]([]T, func(T) bool)` and
`SliceRemoveAllFunc[T]([]T, func(T) bool)` for general use.
- Add comments to explain why not `golang.org/x/exp/slices`.
- Add unit tests.
2023-01-11 08:31:16 +03:00
if util . SliceSortedEqual ( giteaKeys , providedKeys ) {
2021-07-24 13:16:34 +03:00
log . Trace ( "synchronizePublicKeys[%s]: Public Keys are already in sync for %s (Source:%v/DB:%v)" , s . Name , usr . Name , len ( providedKeys ) , len ( giteaKeys ) )
return false
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
log . Trace ( "synchronizePublicKeys[%s]: Public Key needs update for user %s (Source:%v/DB:%v)" , s . Name , usr . Name , len ( providedKeys ) , len ( giteaKeys ) )
2020-10-11 03:38:09 +03:00
2021-07-24 13:16:34 +03:00
// Add new Public SSH Keys that doesn't already exist in DB
var newKeys [ ] string
for _ , key := range providedKeys {
Improve utils of slices (#22379)
- Move the file `compare.go` and `slice.go` to `slice.go`.
- Fix `ExistsInSlice`, it's buggy
- It uses `sort.Search`, so it assumes that the input slice is sorted.
- It passes `func(i int) bool { return slice[i] == target })` to
`sort.Search`, that's incorrect, check the doc of `sort.Search`.
- Conbine `IsInt64InSlice(int64, []int64)` and `ExistsInSlice(string,
[]string)` to `SliceContains[T]([]T, T)`.
- Conbine `IsSliceInt64Eq([]int64, []int64)` and `IsEqualSlice([]string,
[]string)` to `SliceSortedEqual[T]([]T, T)`.
- Add `SliceEqual[T]([]T, T)` as a distinction from
`SliceSortedEqual[T]([]T, T)`.
- Redesign `RemoveIDFromList([]int64, int64) ([]int64, bool)` to
`SliceRemoveAll[T]([]T, T) []T`.
- Add `SliceContainsFunc[T]([]T, func(T) bool)` and
`SliceRemoveAllFunc[T]([]T, func(T) bool)` for general use.
- Add comments to explain why not `golang.org/x/exp/slices`.
- Add unit tests.
2023-01-11 08:31:16 +03:00
if ! util . SliceContainsString ( giteaKeys , key ) {
2021-07-24 13:16:34 +03:00
newKeys = append ( newKeys , key )
}
}
2023-10-11 07:24:07 +03:00
if AddPublicKeysBySource ( ctx , usr , s , newKeys ) {
2021-07-24 13:16:34 +03:00
sshKeysNeedUpdate = true
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
// Mark keys from DB that no longer exist in the source for deletion
var giteaKeysToDelete [ ] string
for _ , giteaKey := range giteaKeys {
Improve utils of slices (#22379)
- Move the file `compare.go` and `slice.go` to `slice.go`.
- Fix `ExistsInSlice`, it's buggy
- It uses `sort.Search`, so it assumes that the input slice is sorted.
- It passes `func(i int) bool { return slice[i] == target })` to
`sort.Search`, that's incorrect, check the doc of `sort.Search`.
- Conbine `IsInt64InSlice(int64, []int64)` and `ExistsInSlice(string,
[]string)` to `SliceContains[T]([]T, T)`.
- Conbine `IsSliceInt64Eq([]int64, []int64)` and `IsEqualSlice([]string,
[]string)` to `SliceSortedEqual[T]([]T, T)`.
- Add `SliceEqual[T]([]T, T)` as a distinction from
`SliceSortedEqual[T]([]T, T)`.
- Redesign `RemoveIDFromList([]int64, int64) ([]int64, bool)` to
`SliceRemoveAll[T]([]T, T) []T`.
- Add `SliceContainsFunc[T]([]T, func(T) bool)` and
`SliceRemoveAllFunc[T]([]T, func(T) bool)` for general use.
- Add comments to explain why not `golang.org/x/exp/slices`.
- Add unit tests.
2023-01-11 08:31:16 +03:00
if ! util . SliceContainsString ( providedKeys , giteaKey ) {
2021-07-24 13:16:34 +03:00
log . Trace ( "synchronizePublicKeys[%s]: Marking Public SSH Key for deletion for user %s: %v" , s . Name , usr . Name , giteaKey )
giteaKeysToDelete = append ( giteaKeysToDelete , giteaKey )
}
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
// Delete keys from DB that no longer exist in the source
2023-10-11 07:24:07 +03:00
needUpd , err := deleteKeysMarkedForDeletion ( ctx , giteaKeysToDelete )
2020-11-28 05:42:08 +03:00
if err != nil {
2021-07-24 13:16:34 +03:00
log . Error ( "synchronizePublicKeys[%s]: Error deleting Public Keys marked for deletion for user %s: %v" , s . Name , usr . Name , err )
2020-11-28 05:42:08 +03:00
}
2021-07-24 13:16:34 +03:00
if needUpd {
sshKeysNeedUpdate = true
2020-10-11 03:38:09 +03:00
}
2021-07-24 13:16:34 +03:00
return sshKeysNeedUpdate
2020-10-11 03:38:09 +03:00
}