Browse Source

Use fingerprint to check instead content for public key (#911)

* use fingerprint to check instead content for public key

* add fingerprint field for ErrKeyAlreadyExist
Lunny Xiao 2 years ago
parent
commit
7eb8daffa3
2 changed files with 47 additions and 26 deletions
  1. 5 3
      models/error.go
  2. 42 23
      models/ssh_key.go

+ 5 - 3
models/error.go

@@ -213,8 +213,9 @@ func (err ErrKeyNotExist) Error() string {
213 213
 
214 214
 // ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error.
215 215
 type ErrKeyAlreadyExist struct {
216
-	OwnerID int64
217
-	Content string
216
+	OwnerID     int64
217
+	Fingerprint string
218
+	Content     string
218 219
 }
219 220
 
220 221
 // IsErrKeyAlreadyExist checks if an error is a ErrKeyAlreadyExist.
@@ -224,7 +225,8 @@ func IsErrKeyAlreadyExist(err error) bool {
224 225
 }
225 226
 
226 227
 func (err ErrKeyAlreadyExist) Error() string {
227
-	return fmt.Sprintf("public key already exists [owner_id: %d, content: %s]", err.OwnerID, err.Content)
228
+	return fmt.Sprintf("public key already exists [owner_id: %d, finter_print: %s, content: %s]",
229
+		err.OwnerID, err.Fingerprint, err.Content)
228 230
 }
229 231
 
230 232
 // ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error.

+ 42 - 23
models/ssh_key.go

@@ -354,41 +354,50 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
354 354
 	return nil
355 355
 }
356 356
 
357
-// checkKeyContent only checks if key content has been used as public key,
357
+// checkKeyFingerprint only checks if key fingerprint has been used as public key,
358 358
 // it is OK to use same key as deploy key for multiple repositories/users.
359
-func checkKeyContent(content string) error {
360
-	has, err := x.Get(&PublicKey{
361
-		Content: content,
362
-		Type:    KeyTypeUser,
359
+func checkKeyFingerprint(e Engine, fingerprint string) error {
360
+	has, err := e.Get(&PublicKey{
361
+		Fingerprint: fingerprint,
362
+		Type:        KeyTypeUser,
363 363
 	})
364 364
 	if err != nil {
365 365
 		return err
366 366
 	} else if has {
367
-		return ErrKeyAlreadyExist{0, content}
367
+		return ErrKeyAlreadyExist{0, fingerprint, ""}
368 368
 	}
369 369
 	return nil
370 370
 }
371 371
 
372
-func addKey(e Engine, key *PublicKey) (err error) {
372
+func calcFingerprint(publicKeyContent string) (string, error) {
373 373
 	// Calculate fingerprint.
374 374
 	tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
375 375
 		"id_rsa.pub"), "\\", "/", -1)
376 376
 	dir := path.Dir(tmpPath)
377 377
 
378 378
 	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
379
-		return fmt.Errorf("Failed to create dir %s: %v", dir, err)
379
+		return "", fmt.Errorf("Failed to create dir %s: %v", dir, err)
380 380
 	}
381 381
 
382
-	if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil {
383
-		return err
382
+	if err := ioutil.WriteFile(tmpPath, []byte(publicKeyContent), 0644); err != nil {
383
+		return "", err
384 384
 	}
385 385
 	stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
386 386
 	if err != nil {
387
-		return fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
387
+		return "", fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
388 388
 	} else if len(stdout) < 2 {
389
-		return errors.New("not enough output for calculating fingerprint: " + stdout)
389
+		return "", errors.New("not enough output for calculating fingerprint: " + stdout)
390
+	}
391
+	return strings.Split(stdout, " ")[1], nil
392
+}
393
+
394
+func addKey(e Engine, key *PublicKey) (err error) {
395
+	if len(key.Fingerprint) <= 0 {
396
+		key.Fingerprint, err = calcFingerprint(key.Content)
397
+		if err != nil {
398
+			return err
399
+		}
390 400
 	}
391
-	key.Fingerprint = strings.Split(stdout, " ")[1]
392 401
 
393 402
 	// Save SSH key.
394 403
 	if _, err = e.Insert(key); err != nil {
@@ -405,7 +414,13 @@ func addKey(e Engine, key *PublicKey) (err error) {
405 414
 // AddPublicKey adds new public key to database and authorized_keys file.
406 415
 func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
407 416
 	log.Trace(content)
408
-	if err := checkKeyContent(content); err != nil {
417
+
418
+	fingerprint, err := calcFingerprint(content)
419
+	if err != nil {
420
+		return nil, err
421
+	}
422
+
423
+	if err := checkKeyFingerprint(x, fingerprint); err != nil {
409 424
 		return nil, err
410 425
 	}
411 426
 
@@ -426,11 +441,12 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
426 441
 	}
427 442
 
428 443
 	key := &PublicKey{
429
-		OwnerID: ownerID,
430
-		Name:    name,
431
-		Content: content,
432
-		Mode:    AccessModeWrite,
433
-		Type:    KeyTypeUser,
444
+		OwnerID:     ownerID,
445
+		Name:        name,
446
+		Fingerprint: fingerprint,
447
+		Content:     content,
448
+		Mode:        AccessModeWrite,
449
+		Type:        KeyTypeUser,
434 450
 	}
435 451
 	if err = addKey(sess, key); err != nil {
436 452
 		return nil, fmt.Errorf("addKey: %v", err)
@@ -665,14 +681,15 @@ func HasDeployKey(keyID, repoID int64) bool {
665 681
 
666 682
 // AddDeployKey add new deploy key to database and authorized_keys file.
667 683
 func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) {
668
-	if err := checkKeyContent(content); err != nil {
684
+	fingerprint, err := calcFingerprint(content)
685
+	if err != nil {
669 686
 		return nil, err
670 687
 	}
671 688
 
672 689
 	pkey := &PublicKey{
673
-		Content: content,
674
-		Mode:    AccessModeRead,
675
-		Type:    KeyTypeDeploy,
690
+		Fingerprint: fingerprint,
691
+		Mode:        AccessModeRead,
692
+		Type:        KeyTypeDeploy,
676 693
 	}
677 694
 	has, err := x.Get(pkey)
678 695
 	if err != nil {
@@ -687,6 +704,8 @@ func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) {
687 704
 
688 705
 	// First time use this deploy key.
689 706
 	if !has {
707
+		pkey.Content = content
708
+		pkey.Name = name
690 709
 		if err = addKey(sess, pkey); err != nil {
691 710
 			return nil, fmt.Errorf("addKey: %v", err)
692 711
 		}