objective categorical abstract machine language personal data server

Preserve existing non-PDS rotation keys in migration

futur.blue a871067c 5d2164aa

verified
+128 -138
+125 -136
pegasus/lib/api/account_/migrate.ml
··· 1574 1574 ~handle:state.handle ~old_pds:state.old_pds 1575 1575 "Please enter the PLC token from your email" 1576 1576 else 1577 - (* Get our recommended credentials *) 1577 + (* new rotation keys = current rotation keys - old PDS key(s) + new PDS key *) 1578 + let%lwt old_pds_keys = 1579 + match%lwt 1580 + get_remote_recommended_credentials 1581 + ~pds_endpoint:state.old_pds ~access_jwt:state.access_jwt 1582 + with 1583 + | Ok creds -> 1584 + Lwt.return creds.rotation_keys 1585 + | Error e -> 1586 + Dream.warning (fun log -> 1587 + log 1588 + "migration %s: failed to get old PDS \ 1589 + credentials: %s" 1590 + state.did e ) ; 1591 + Lwt.return [] 1592 + in 1593 + let%lwt current_keys = 1594 + match%lwt get_plc_rotation_keys ~did:state.did with 1595 + | Ok keys -> 1596 + Lwt.return keys 1597 + | Error _ -> 1598 + Lwt.return [] 1599 + in 1600 + (* remove old PDS key(s) from current keys *) 1601 + let keys_to_preserve = 1602 + List.filter 1603 + (fun k -> not (List.mem k old_pds_keys)) 1604 + current_keys 1605 + in 1606 + (* construct recommended credentials *) 1578 1607 match%lwt 1579 1608 get_recommended_did_credentials state.did ctx.db 1609 + ~extra_rotation_keys:keys_to_preserve 1580 1610 with 1581 1611 | Error e -> 1582 1612 render_error ~step:"enter_plc_token" ~did:state.did 1583 1613 ~handle:state.handle ~old_pds:state.old_pds 1584 1614 ("Failed to get credentials: " ^ e) 1585 - | Ok base_credentials -> ( 1586 - (* new rotation keys = current rotation keys - old PDS key(s) + new PDS key *) 1587 - let%lwt merged_credentials = 1588 - let%lwt old_pds_keys = 1589 - match%lwt 1590 - get_remote_recommended_credentials 1591 - ~pds_endpoint:state.old_pds 1592 - ~access_jwt:state.access_jwt 1593 - with 1594 - | Ok creds -> 1595 - Lwt.return creds.rotation_keys 1596 - | Error e -> 1597 - Dream.warning (fun log -> 1598 - log 1599 - "migration %s: failed to get old PDS \ 1600 - credentials: %s" 1601 - state.did e ) ; 1602 - Lwt.return [] 1603 - in 1604 - let%lwt current_keys = 1605 - match%lwt get_plc_rotation_keys ~did:state.did with 1606 - | Ok keys -> 1607 - Lwt.return keys 1608 - | Error _ -> 1609 - Lwt.return [] 1610 - in 1611 - (* remove old PDS key(s) from current keys *) 1612 - let preserved_keys = 1613 - List.filter 1614 - (fun k -> not (List.mem k old_pds_keys)) 1615 - current_keys 1616 - in 1617 - (* then add in new key *) 1618 - let merged_keys = 1619 - preserved_keys @ base_credentials.rotation_keys 1620 - |> List.sort_uniq String.compare 1621 - in 1622 - Lwt.return 1623 - {base_credentials with rotation_keys= merged_keys} 1624 - in 1625 - (* get old pds to sign plc operation *) 1615 + | Ok credentials -> ( 1616 + (* get old pds to sign plc operation *) 1617 + match%lwt 1618 + sign_plc_operation ~pds_endpoint:state.old_pds 1619 + ~access_jwt:state.access_jwt ~token:plc_token 1620 + ~credentials 1621 + with 1622 + | Error e -> 1623 + render_error ~step:"enter_plc_token" ~did:state.did 1624 + ~handle:state.handle ~old_pds:state.old_pds 1625 + ("Failed to sign PLC operation: " ^ e) 1626 + | Ok signed_operation -> ( 1627 + (* submit plc operation *) 1626 1628 match%lwt 1627 - sign_plc_operation ~pds_endpoint:state.old_pds 1628 - ~access_jwt:state.access_jwt ~token:plc_token 1629 - ~credentials:merged_credentials 1629 + submit_plc_operation ~did:state.did ~handle:state.handle 1630 + ~operation:signed_operation ctx.db 1630 1631 with 1631 1632 | Error e -> 1632 1633 render_error ~step:"enter_plc_token" ~did:state.did 1633 1634 ~handle:state.handle ~old_pds:state.old_pds 1634 - ("Failed to sign PLC operation: " ^ e) 1635 - | Ok signed_operation -> ( 1636 - (* submit plc operation *) 1637 - match%lwt 1638 - submit_plc_operation ~did:state.did 1639 - ~handle:state.handle ~operation:signed_operation 1640 - ctx.db 1641 - with 1642 - | Error e -> 1643 - render_error ~step:"enter_plc_token" ~did:state.did 1644 - ~handle:state.handle ~old_pds:state.old_pds 1645 - ("Failed to submit PLC operation: " ^ e) 1646 - | Ok () -> 1647 - (* log account status before activation *) 1648 - let%lwt () = 1635 + ("Failed to submit PLC operation: " ^ e) 1636 + | Ok () -> 1637 + (* log account status before activation *) 1638 + let%lwt () = 1639 + match%lwt 1640 + check_local_account_status ~did:state.did 1641 + with 1642 + | Ok status -> 1643 + Dream.info (fun log -> 1644 + log 1645 + "migration %s: activating account, \ 1646 + imported_blobs=%d/%d" 1647 + state.did status.imported_blobs 1648 + status.expected_blobs ) ; 1649 + Lwt.return_unit 1650 + | Error e -> 1651 + Dream.warning (fun log -> 1652 + log 1653 + "migration %s: failed to check status \ 1654 + before activation: %s" 1655 + state.did e ) ; 1656 + Lwt.return_unit 1657 + in 1658 + (* activate the account *) 1659 + let%lwt () = activate_account state.did ctx.db in 1660 + let%lwt () = Session.log_in_did ctx.req state.did in 1661 + let%lwt () = clear_migration_state ctx.req in 1662 + (* try deactivating old account with current token, refresh if expired *) 1663 + let%lwt deactivation_result = 1664 + match%lwt 1665 + deactivate_old_account ~pds_endpoint:state.old_pds 1666 + ~access_jwt:state.access_jwt 1667 + with 1668 + | Ok () -> 1669 + Lwt.return_ok () 1670 + | Error e 1671 + when Util.str_contains ~affix:"401" e 1672 + || Util.str_contains ~affix:"Unauthorized" e 1673 + -> ( 1649 1674 match%lwt 1650 - check_local_account_status ~did:state.did 1675 + refresh_session ~pds_endpoint:state.old_pds 1676 + ~refresh_jwt:state.refresh_jwt 1651 1677 with 1652 - | Ok status -> 1653 - Dream.info (fun log -> 1654 - log 1655 - "migration %s: activating account, \ 1656 - imported_blobs=%d/%d" 1657 - state.did status.imported_blobs 1658 - status.expected_blobs ) ; 1659 - Lwt.return_unit 1660 - | Error e -> 1661 - Dream.warning (fun log -> 1662 - log 1663 - "migration %s: failed to check status \ 1664 - before activation: %s" 1665 - state.did e ) ; 1666 - Lwt.return_unit 1667 - in 1668 - (* activate the account *) 1669 - let%lwt () = activate_account state.did ctx.db in 1670 - let%lwt () = Session.log_in_did ctx.req state.did in 1671 - let%lwt () = clear_migration_state ctx.req in 1672 - (* try deactivating old account with current token, refresh if expired *) 1673 - let%lwt deactivation_result = 1674 - match%lwt 1675 - deactivate_old_account 1676 - ~pds_endpoint:state.old_pds 1677 - ~access_jwt:state.access_jwt 1678 - with 1679 - | Ok () -> 1680 - Lwt.return_ok () 1681 - | Error e 1682 - when Util.str_contains ~affix:"401" e 1683 - || Util.str_contains ~affix:"Unauthorized" 1684 - e -> ( 1685 - match%lwt 1686 - refresh_session ~pds_endpoint:state.old_pds 1687 - ~refresh_jwt:state.refresh_jwt 1688 - with 1689 - | Ok tokens -> 1690 - deactivate_old_account 1691 - ~pds_endpoint:state.old_pds 1692 - ~access_jwt:tokens.access_jwt 1693 - | Error refresh_err -> 1694 - Lwt.return_error 1695 - (Printf.sprintf 1696 - "Token expired and refresh failed: %s" 1697 - refresh_err ) ) 1698 - | Error e -> 1699 - Lwt.return_error e 1700 - in 1701 - let ( old_account_deactivated 1702 - , old_account_deactivation_error ) = 1703 - match deactivation_result with 1704 - | Ok () -> 1705 - (true, None) 1706 - | Error e -> 1707 - Dream.warning (fun log -> 1708 - log 1709 - "migration %s: failed to deactivate \ 1710 - old account: %s" 1711 - state.did e ) ; 1712 - (false, Some e) 1713 - in 1714 - Util.render_html ~title:"Migrate Account" 1715 - (module Frontend.MigratePage) 1716 - ~props: 1717 - (make_props ~step:"complete" ~did:state.did 1718 - ~handle:state.handle 1719 - ~blobs_imported:state.blobs_imported 1720 - ~blobs_failed:state.blobs_failed 1721 - ~old_account_deactivated 1722 - ?old_account_deactivation_error 1723 - ~message: 1724 - "Your account has been successfully \ 1725 - migrated!" 1726 - () ) ) ) ) ) 1678 + | Ok tokens -> 1679 + deactivate_old_account 1680 + ~pds_endpoint:state.old_pds 1681 + ~access_jwt:tokens.access_jwt 1682 + | Error refresh_err -> 1683 + Lwt.return_error 1684 + (Printf.sprintf 1685 + "Token expired and refresh failed: %s" 1686 + refresh_err ) ) 1687 + | Error e -> 1688 + Lwt.return_error e 1689 + in 1690 + let ( old_account_deactivated 1691 + , old_account_deactivation_error ) = 1692 + match deactivation_result with 1693 + | Ok () -> 1694 + (true, None) 1695 + | Error e -> 1696 + Dream.warning (fun log -> 1697 + log 1698 + "migration %s: failed to deactivate old \ 1699 + account: %s" 1700 + state.did e ) ; 1701 + (false, Some e) 1702 + in 1703 + Util.render_html ~title:"Migrate Account" 1704 + (module Frontend.MigratePage) 1705 + ~props: 1706 + (make_props ~step:"complete" ~did:state.did 1707 + ~handle:state.handle 1708 + ~blobs_imported:state.blobs_imported 1709 + ~blobs_failed:state.blobs_failed 1710 + ~old_account_deactivated 1711 + ?old_account_deactivation_error 1712 + ~message: 1713 + "Your account has been successfully \ 1714 + migrated!" 1715 + () ) ) ) ) ) 1727 1716 | "resend_plc_token" -> ( 1728 1717 match get_migration_state ctx.req with 1729 1718 | None ->
+3 -2
pegasus/lib/api/identity/getRecommendedDidCredentials.ml
··· 1 1 type response = Plc.credentials [@@deriving yojson {strict= false}] 2 2 3 - let get_credentials did db = 3 + let get_credentials did ?(extra_rotation_keys = []) db = 4 4 match%lwt Data_store.get_actor_by_identifier did db with 5 5 | None -> 6 6 Lwt.return_error "actor not found" ··· 8 8 actor.signing_key |> Kleidos.parse_multikey_str |> Kleidos.derive_pubkey 9 9 |> Kleidos.pubkey_to_did_key 10 10 |> (fun did_key -> 11 - Plc.create_did_credentials Env.rotation_key did_key actor.handle ) 11 + Plc.create_did_credentials Env.rotation_key did_key actor.handle 12 + ~rotation_did_keys:extra_rotation_keys ) 12 13 |> Lwt.return_ok 13 14 14 15 let handler =