sliftutils 1.8.6 → 1.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "1.8.6",
3
+ "version": "1.8.7",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -79,11 +79,12 @@ export async function readRemoteRevocations(config: { sourceURL: string }) {
79
79
  return revocations;
80
80
  }
81
81
 
82
- /** Which keys in a repo are revoked. What signfiles and securessh refuse over. */
83
- export async function revokedKeysInRepo(config: { repoPath: string; sourceURL: string }) {
84
- let { repoPath, sourceURL } = config;
85
- let revocations = await readRemoteRevocations({ sourceURL });
86
- let revokedFingerprints = new Set(revocations.map(revocation => revocation.fingerprint));
82
+ /** What the unrevokes already in a repo allow: "<identity> <address>" for each pair, plus the bare
83
+ revocation ids the older format named.
84
+
85
+ Read out of the repo rather than out of the daemon's absorbed state, because whoever runs a cli
86
+ is looking at a checkout and has no daemon in the process to ask. */
87
+ export async function readUnrevokedInRepo(repoPath: string) {
87
88
  let unrevoked = new Set<string>();
88
89
  try {
89
90
  let directory = path.join(repoPath, UNREVOKES_DIR);
@@ -93,7 +94,10 @@ export async function revokedKeysInRepo(config: { repoPath: string; sourceURL: s
93
94
  }
94
95
  let parsed = JSON.parse(await fs.readFile(path.join(directory, name), "utf8"));
95
96
  for (let allowed of parsed.allowed || []) {
96
- unrevoked.add(`${allowed.fingerprint || allowed.machineId} ${allowed.ip}`);
97
+ let identity = allowed.fingerprint || allowed.machineId;
98
+ if (identity && allowed.ip) {
99
+ unrevoked.add(`${identity} ${allowed.ip}`);
100
+ }
97
101
  }
98
102
  // Named ids, for the unrevokes written before this was about pairs.
99
103
  for (let revocationId of parsed.revocationIds || []) {
@@ -103,8 +107,27 @@ export async function revokedKeysInRepo(config: { repoPath: string; sourceURL: s
103
107
  } catch (e) {
104
108
  // Nothing has been unrevoked.
105
109
  }
106
- let stillRevoked = revocations.filter(revocation => !unrevoked.has(revocation.revocationId)
107
- && !unrevoked.has(`${revocation.fingerprint} ${revocationIP(revocation)}`));
110
+ return unrevoked;
111
+ }
112
+
113
+ /** The revocations those unrevokes have not already undone.
114
+
115
+ Matched on revocationIdentity, not on fingerprint: a machine revocation carries a machineId and
116
+ no fingerprint, so comparing fingerprints leaves every machine looking revoked forever no matter
117
+ how many times it is unrevoked. */
118
+ export function stillRevokedBy(revocations: Revocation[], unrevoked: Set<string>) {
119
+ return revocations.filter(revocation =>
120
+ !unrevoked.has(revocation.revocationId)
121
+ && !unrevoked.has(`${revocationIdentity(revocation)} ${revocationIP(revocation)}`)
122
+ );
123
+ }
124
+
125
+ /** Which keys in a repo are revoked. What signfiles and securessh refuse over. */
126
+ export async function revokedKeysInRepo(config: { repoPath: string; sourceURL: string }) {
127
+ let { repoPath, sourceURL } = config;
128
+ let revocations = await readRemoteRevocations({ sourceURL });
129
+ let unrevoked = await readUnrevokedInRepo(repoPath);
130
+ let stillRevoked = stillRevokedBy(revocations, unrevoked);
108
131
  let keys = normalizeKeys(await fs.readFile(path.join(repoPath, "authorized_keys"), "utf8").catch(() => ""));
109
132
  return stillRevoked
110
133
  .filter(revocation => keys.some(key => keyFingerprint(key) === revocation.fingerprint))
@@ -6,7 +6,7 @@ import { revokeRepoURL } from "./revokeSource";
6
6
  import { signRepo } from "../signedFiles/signFiles";
7
7
  import { getMachines, setMachines } from "../machines/machines";
8
8
  import { resolveKeysRepo } from "./keysRepo";
9
- import { readRemoteRevocations, Revocation, revocationIdentity, revocationIP, UNREVOKES_DIR } from "./unrevoke";
9
+ import { readRemoteRevocations, readUnrevokedInRepo, Revocation, revocationIdentity, revocationIP, stillRevokedBy, UNREVOKES_DIR } from "./unrevoke";
10
10
 
11
11
  const GIT_KEYWORD = "git";
12
12
  const COMMIT_MESSAGE = "unrevoke keys";
@@ -104,6 +104,18 @@ async function main() {
104
104
  return;
105
105
  }
106
106
 
107
+ // Only what this repo has not already forgiven. Revocations are never deleted from the revoke
108
+ // repo, so without this every run writes a fresh unrevoke naming every revocation that ever
109
+ // happened - the same entries listed and re-signed each time, which reads as though unrevoking
110
+ // does nothing at all.
111
+ let alreadyUnrevoked = await readUnrevokedInRepo(repoPath);
112
+ revocations = stillRevokedBy(revocations, alreadyUnrevoked);
113
+ if (!revocations.length) {
114
+ console.log(`Everything ${revokeRepoURL(originURL)} lists is already unrevoked here.`);
115
+ console.log(`Nothing to do, and nothing was written.`);
116
+ return;
117
+ }
118
+
107
119
  let directory = path.join(repoPath, UNREVOKES_DIR);
108
120
  await fs.mkdir(directory, { recursive: true });
109
121
  let stamp = new Date().toISOString().replace(/[:.]/g, "-");