Check-in [acfaf4e48e]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the ability to rotate the captcha-secret, setting up a new secret that is common to all members of a login-group.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: acfaf4e48e776d84222cdad6cda8dbb4b39c49607494de5057b7e744173dc697
User & Date: drh 2024-08-23 14:43:53.675
Context
2024-08-23
15:42
Improved instructions for setting a common captcha-secret across a login-group on the /setup_login_group page. check-in: 404f15501b user: drh tags: trunk
14:43
Add the ability to rotate the captcha-secret, setting up a new secret that is common to all members of a login-group. check-in: acfaf4e48e user: drh tags: trunk
13:55
Allow for multiple captcha-secret values. The primary is still 'captcha-secret'. Backups are in 'captcha-secret-N' where N is a small integer. The backups are only valid for 6 hours. This allows the captcha-secret to be changed without disrupting anonymous logins and/or captcha dialogs that are in progress when the secret changes. check-in: 8659d84aff user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/captcha.c.
506
507
508
509
510
511
512
















































513
514
515
516
517
518
519
*/
unsigned int captcha_seed(void){
  unsigned int x;
  sqlite3_randomness(sizeof(x), &x);
  x &= 0x7fffffff;
  return x;
}

















































/*
** Return the value of the N-th more recent captcha-secret.  The
** most recent captch-secret is 0.  Others are prior captcha-secrets
** that have expired, but are retained for a limited period of time
** so that pending anonymous login cookies and/or captcha dialogs
** don't malfunction when the captcha-secret changes.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
*/
unsigned int captcha_seed(void){
  unsigned int x;
  sqlite3_randomness(sizeof(x), &x);
  x &= 0x7fffffff;
  return x;
}

/* The SQL that will rotate the the captcha-secret. */
static const char captchaSecretRotationSql[] = 
@ SAVEPOINT rotate;
@ DELETE FROM config
@  WHERE name GLOB 'captcha-secret-*'
@    AND mtime<unixepoch('now','-6 hours');
@ UPDATE config
@    SET name=format('captcha-secret-%%d',substr(name,16)+1)
@  WHERE name GLOB 'captcha-secret-*';
@ UPDATE config
@    SET name='captcha-secret-1', mtime=unixepoch()
@  WHERE name='captcha-secret';
@ REPLACE INTO config(name,value,mtime)
@   VALUES('captcha-secret',%Q,unixepoch());
@ RELEASE rotate;
;


/*
** Create a new random captcha-secret.  Rotate the old one into
** the captcha-secret-N backups.  Purge captch-secret-N backups
** older than 6 hours.
**
** Do this on the current database and in all other databases of
** the same login group.
*/
void captcha_secret_rotate(void){
  char *zNew = db_text(0, "SELECT lower(hex(randomblob(20)))");
  char *zSql = mprintf(captchaSecretRotationSql/*works-like:"%Q"*/, zNew);
  char *zErrs = 0;
  fossil_free(zNew);
  db_unprotect(PROTECT_CONFIG);
  db_begin_transaction();
  sqlite3_exec(g.db, zSql, 0, 0, &zErrs);
  db_protect_pop();
  if( zErrs && zErrs[0] ){
    db_rollback_transaction();
    fossil_fatal("Unable to rotate captcha-secret\n%s\nERROR: %s\n",
                 zSql, zErrs);
  }
  db_end_transaction(0);
  login_group_sql(zSql, "", "", &zErrs);
  if( zErrs ){
    sqlite3_free(zErrs);  /* Silently ignore errors on other repos */
  }
  fossil_free(zSql);
}

/*
** Return the value of the N-th more recent captcha-secret.  The
** most recent captch-secret is 0.  Others are prior captcha-secrets
** that have expired, but are retained for a limited period of time
** so that pending anonymous login cookies and/or captcha dialogs
** don't malfunction when the captcha-secret changes.
Changes to src/setup.c.
778
779
780
781
782
783
784


785
786
787
788
789
790
791
  file_canonical_name(g.zRepositoryName, &fullName, 0);
  zSelfRepo = fossil_strdup(blob_str(&fullName));
  blob_reset(&fullName);
  if( P("join")!=0 ){
    login_group_join(zRepo, 1, zLogin, zPw, zNewName, &zErrMsg);
  }else if( P("leave") ){
    login_group_leave(&zErrMsg);


  }
  style_set_current_feature("setup");
  style_header("Login Group Configuration");
  if( zErrMsg ){
    @ <p class="generalError">%s(zErrMsg)</p>
  }
  zGroup = login_group_name();







>
>







778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  file_canonical_name(g.zRepositoryName, &fullName, 0);
  zSelfRepo = fossil_strdup(blob_str(&fullName));
  blob_reset(&fullName);
  if( P("join")!=0 ){
    login_group_join(zRepo, 1, zLogin, zPw, zNewName, &zErrMsg);
  }else if( P("leave") ){
    login_group_leave(&zErrMsg);
  }else if( P("rotate") ){
    captcha_secret_rotate();
  }
  style_set_current_feature("setup");
  style_header("Login Group Configuration");
  if( zErrMsg ){
    @ <p class="generalError">%s(zErrMsg)</p>
  }
  zGroup = login_group_name();
847
848
849
850
851
852
853
854
855



856
857
858
859
860
861
862
      @ <td>%h(zTitle)<td width="10"><td>%h(zRepo)</tr>
    }
    db_finalize(&q);
    @ </table>
    @
    @ <p><form action="%R/setup_login_group" method="post"><div>
    login_insert_csrf_secret();
    @ To leave this login group press
    @ <input type="submit" value="Leave Login Group" name="leave">



    @ </form></p>
  }
  @ <hr><h2>Implementation Details</h2>
  @ <p>The following are fields from the CONFIG table related to login-groups.
  @ </p>
  @ <table border='1' cellspacing="0" cellpadding="4"\
  @ class='sortable' data-column-types='ttt' data-init-sort='1'>







|

>
>
>







849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
      @ <td>%h(zTitle)<td width="10"><td>%h(zRepo)</tr>
    }
    db_finalize(&q);
    @ </table>
    @
    @ <p><form action="%R/setup_login_group" method="post"><div>
    login_insert_csrf_secret();
    @ <p>To leave this login group press:
    @ <input type="submit" value="Leave Login Group" name="leave">
    @ <p>To rotate the captcha-secret on all members of the login-group
    @ so that they can all share anonymous logins, press:
    @ <input type="submit" name="rotate" value="Rotate the captcha-secret">
    @ </form></p>
  }
  @ <hr><h2>Implementation Details</h2>
  @ <p>The following are fields from the CONFIG table related to login-groups.
  @ </p>
  @ <table border='1' cellspacing="0" cellpadding="4"\
  @ class='sortable' data-column-types='ttt' data-init-sort='1'>