@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3// Previously, MFA factors for individual users were bound to raw factor types.
4// The only factor type ever implemented in the upstream was "totp".
5
6// Going forward, individual factors are bound to a provider instead. This
7// allows factor types to have some configuration, like API keys for
8// service-based MFA. It also allows installs to select which types of factors
9// they want users to be able to set up.
10
11// Migrate all existing TOTP factors to the first available TOTP provider,
12// creating one if none exists. This migration is a little bit messy, but
13// gives us a clean slate going forward with no "builtin" providers.
14
15$table = new PhabricatorAuthFactorConfig();
16$conn = $table->establishConnection('w');
17
18$provider_table = new PhabricatorAuthFactorProvider();
19$provider_phid = null;
20$iterator = new LiskRawMigrationIterator($conn, $table->getTableName());
21$totp_key = 'totp';
22foreach ($iterator as $row) {
23
24 // This wasn't a TOTP factor, so skip it.
25 if ($row['factorKey'] !== $totp_key) {
26 continue;
27 }
28
29 // This factor already has an associated provider.
30 if (strlen($row['factorProviderPHID'])) {
31 continue;
32 }
33
34 // Find (or create) a suitable TOTP provider. Note that we can't "save()"
35 // an object or this migration will break if the object ever gets new
36 // columns; just INSERT the raw fields instead.
37
38 if ($provider_phid === null) {
39 $provider_row = queryfx_one(
40 $conn,
41 'SELECT phid FROM %R WHERE providerFactorKey = %s LIMIT 1',
42 $provider_table,
43 $totp_key);
44
45 if ($provider_row) {
46 $provider_phid = $provider_row['phid'];
47 } else {
48 $provider_phid = $provider_table->generatePHID();
49 queryfx(
50 $conn,
51 'INSERT INTO %R
52 (phid, providerFactorKey, name, status, properties,
53 dateCreated, dateModified)
54 VALUES (%s, %s, %s, %s, %s, %d, %d)',
55 $provider_table,
56 $provider_phid,
57 $totp_key,
58 '',
59 'active',
60 '{}',
61 PhabricatorTime::getNow(),
62 PhabricatorTime::getNow());
63 }
64 }
65
66 queryfx(
67 $conn,
68 'UPDATE %R SET factorProviderPHID = %s WHERE id = %d',
69 $table,
70 $provider_phid,
71 $row['id']);
72}