auroq-os 2.8.9 → 2.8.10
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/.auroq-core/core-config.yaml +1 -1
- package/CHANGELOG.md +1 -0
- package/README.md +3 -3
- package/installer/install.ps1 +2 -2
- package/installer/install.sh +2 -2
- package/lib/cofre.js +28 -7
- package/lib/infisical-cli.js +98 -1
- package/lib/onepassword.js +54 -15
- package/lib/runtime-integrity.json +6 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
- 2.8.10 — Cofre no Mac, segunda rodada do teste real num usuário novo do macOS (07/11/2026). **Guardar senha no 1Password voltou a funcionar:** no 1Password CLI 2.41, o molde do item por pipe parou de funcionar (`item create -` recusa com "provide the item category" e `item edit` por pipe sai 0 sem mudar nada); `segredo gravar` e a cópia da chave no cofre pessoal passam a usar o molde num arquivo temporário só do usuário (`--template`, apagado em seguida), como o Windows já fazia. **Mac, "acessar dados de outros apps":** o `op` lê a pasta do 1Password e o Mac pergunta se o Auroq OS (ou o Terminal) pode acessar dados de outros apps; negada ou cancelada, a conta some e o aluno ouvia "ligue a integração" em laço. Agora, sem conta à vista no Mac, o comando zera só essa decisão do programa que o abriu (`tccutil reset SystemPolicyAppData <app>`) para a pergunta voltar e diz para clicar em Permitir. O atalho para Configurações > Desenvolvedor abre o 1Password atual, não o "1Password 7" antigo. **Infisical no Safari:** a página do Infisical não consegue entregar o login ao computador no Safari e mostra "Unable to reach CLI" com "Copy to clipboard"; sem terminal o programa do Infisical não aceitava colar. Agora, enquanto o login espera (Mac e Windows), o comando reconhece esse código na área de transferência (só esse formato), entrega ao programa pelo endereço local e limpa a área de transferência: o aluno só clica em "Copy to clipboard". Textos do Mac: "Desbloquear usando Touch ID" e, sem Touch ID, a janela pede só "Autorizar". Catálogo `auroq-core` 2.3.56 (peça do 1Password da skill do cofre).
|
|
3
4
|
- 2.8.9 — 1Password no Mac sem Homebrew (teste real num usuário novo do macOS, 06/11/2026): o Mac de aluno não tem Homebrew, e o `conectar-1password` parava em `app-nao-instalou` e `sem-op`. Agora, sem Homebrew (ou se ele falhar), o comando baixa o app oficial do 1Password (`1Password-latest`, assinatura da AgileBits conferida com `codesign --deep` e Team ID 2BUA8C4S2C) e copia para a pasta Aplicativos, e instala o 1Password CLI 2.41.1 oficial (SHA-256 fixo, o mesmo do app Auroq OS, mais a assinatura) em `~/.auroq/op/bin`, sem senha de administrador. `segredo` acha o `op` nessa pasta mesmo num terminal que não a tem no PATH.
|
|
4
5
|
- 1Password no Windows: o CLI do 1Password passa pelo PowerShell, como no teste real do Marcos; isso evita a falha de sessão que ocorria quando o Node o iniciava diretamente. `--estado` usa o mesmo caminho para detectar o CLI, e a lista de contas deixa de depender do shell em que o aluno abriu o comando. Os três ganchos do Claude Code usam o caminho do projeto mesmo depois de entrar numa subpasta. A skill do cofre orienta o diagnóstico quando a aprovação se repete. Catálogo `auroq-core` 2.3.55.
|
|
5
6
|
|
package/README.md
CHANGED
|
@@ -290,13 +290,13 @@ a parte tecnica e com o Companion.
|
|
|
290
290
|
|
|
291
291
|
## Observabilidade e integridade do motor
|
|
292
292
|
|
|
293
|
-
Apos publicacao, `npx -y auroq-os@2.8.
|
|
294
|
-
manutencao/diagnostico. `npx -y auroq-os@2.8.
|
|
293
|
+
Apos publicacao, `npx -y auroq-os@2.8.10 doctor` mostra a fila local segura e os comandos pinados de
|
|
294
|
+
manutencao/diagnostico. `npx -y auroq-os@2.8.10 manutencao` preserva o caminho existente
|
|
295
295
|
de consentimento legado, studentFiles, customizacoes e dados do negocio. Nao ha
|
|
296
296
|
migracao forcada. O registro MCP aponta para `arcane-mcp@0.7.1` — o pin mora no campo
|
|
297
297
|
`arcaneMcpPin` do package.json (fonte unica; o servidor le o mesmo campo no npm).
|
|
298
298
|
`npm run release:verify` recusa publicar com um pin que o npm nao resolva.
|
|
299
|
-
Os instaladores do repositorio ficam preparados para 2.8.
|
|
299
|
+
Os instaladores do repositorio ficam preparados para 2.8.10; as copias publicas so recebem
|
|
300
300
|
a versao apos os gates nativos e a verificacao do tarball publicado.
|
|
301
301
|
O pacote inclui `lib/runtime-integrity.json`: inventario SHA-256 gerado depois da montagem da casca, verificavel com `npm run integrity:verify` dentro do pacote extraido. Ele comprova consistencia do conteudo; nao e uma assinatura de autoria.
|
|
302
302
|
|
package/installer/install.ps1
CHANGED
|
@@ -589,7 +589,7 @@ function Invoke-AuroqLogin {
|
|
|
589
589
|
# sucesso. Usado como pergunta de sim/nao, ele dizia "voce ja estava logado"
|
|
590
590
|
# pra quem nunca logou, pulava o portao e deixava a conta sem acesso chegar ate
|
|
591
591
|
# a criacao da pasta.
|
|
592
|
-
& (Get-AuroqNpx) -y auroq-os@2.8.
|
|
592
|
+
& (Get-AuroqNpx) -y auroq-os@2.8.10 check-access
|
|
593
593
|
if ($LASTEXITCODE -ne 0) {
|
|
594
594
|
Write-AuroqLog 'login' 'recusado'
|
|
595
595
|
Write-Host ''
|
|
@@ -677,7 +677,7 @@ function Invoke-AuroqInit {
|
|
|
677
677
|
if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Sistema - seria montado aqui'; return }
|
|
678
678
|
|
|
679
679
|
Set-Location $script:AuroqPastaAlvo
|
|
680
|
-
& (Get-AuroqNpx) -y auroq-os@2.8.
|
|
680
|
+
& (Get-AuroqNpx) -y auroq-os@2.8.10 instalar
|
|
681
681
|
if ($LASTEXITCODE -ne 0) {
|
|
682
682
|
Write-AuroqLog 'init' 'falhou'
|
|
683
683
|
Write-AuroqErro 'A montagem do sistema parou no meio.' 'Rode o mesmo comando de novo. Se repetir, mande pro suporte o arquivo install.log da pasta .auroq.'
|
package/installer/install.sh
CHANGED
|
@@ -219,9 +219,9 @@ auroq_tem_terminal() {
|
|
|
219
219
|
# recebem pedaco do script no lugar da resposta dele.
|
|
220
220
|
auroq_npx_aluno() {
|
|
221
221
|
if [ -t 0 ]; then
|
|
222
|
-
npx -y auroq-os@2.8.
|
|
222
|
+
npx -y auroq-os@2.8.10 "$@"
|
|
223
223
|
else
|
|
224
|
-
npx -y auroq-os@2.8.
|
|
224
|
+
npx -y auroq-os@2.8.10 "$@" < /dev/tty
|
|
225
225
|
fi
|
|
226
226
|
}
|
|
227
227
|
|
package/lib/cofre.js
CHANGED
|
@@ -521,7 +521,7 @@ function makeOpBackend(d) {
|
|
|
521
521
|
return recomposicao;
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
-
async function call(tk, args, input = '') {
|
|
524
|
+
async function call(tk, args, input = '', extra = {}) {
|
|
525
525
|
const o = mod(d, 'onepassword');
|
|
526
526
|
const run = d.op || o.runOp;
|
|
527
527
|
// o ambiente e montado a cada tentativa: o PATH recomposto vale so para quem copia process.env DEPOIS
|
|
@@ -532,7 +532,7 @@ function makeOpBackend(d) {
|
|
|
532
532
|
for (const k of Object.keys(env)) {
|
|
533
533
|
if (/^AUROQ_INFISICAL_/i.test(k)) delete env[k];
|
|
534
534
|
}
|
|
535
|
-
return run(args, { env, input, timeoutMs: OP_TIMEOUT_MS });
|
|
535
|
+
return run(args, { env, input, timeoutMs: OP_TIMEOUT_MS, ...extra });
|
|
536
536
|
};
|
|
537
537
|
let r = await tentar();
|
|
538
538
|
if (r && r.missing && (ehWindows(d) || ehMac(d)) && (await recomporPathUmaVez())) r = await tentar();
|
|
@@ -541,16 +541,37 @@ function makeOpBackend(d) {
|
|
|
541
541
|
|
|
542
542
|
const semChave = () => failure('cofre-nao-configurado', tipo);
|
|
543
543
|
|
|
544
|
+
/**
|
|
545
|
+
* Criar e editar item vao com o molde num arquivo temporario (`--template`), nunca por pipe: no 1Password CLI 2.41
|
|
546
|
+
* (teste real num Mac, 07/11/2026) o `item create -` por pipe recusa ("provide the item category with '--category'
|
|
547
|
+
* flag") e o `item edit` por pipe sai 0 SEM mudar nada. O arquivo (so deste usuario, 0600) e apagado em seguida,
|
|
548
|
+
* aconteca o que acontecer; o `op` roda com o stdin desligado (com `--template` ele nao aceita pipe nenhum).
|
|
549
|
+
*/
|
|
550
|
+
async function runComMolde(args, body, secrets) {
|
|
551
|
+
const o = mod(d, 'onepassword');
|
|
552
|
+
let tmp = null;
|
|
553
|
+
try {
|
|
554
|
+
tmp = o.writeTemplateFile(body);
|
|
555
|
+
} catch (e) {
|
|
556
|
+
return { erro: failure('falha', tipo, `Nao consegui preparar o arquivo temporario do molde (${oneLine(e && e.message, 120)}).`) };
|
|
557
|
+
}
|
|
558
|
+
try {
|
|
559
|
+
return await run([...args, '--template', tmp.file], undefined, secrets, { noStdin: true });
|
|
560
|
+
} finally {
|
|
561
|
+
try { fs.rmSync(tmp.dir, { recursive: true, force: true }); } catch { /* fica na pasta temporaria do usuario */ }
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
544
565
|
/** Gravar e apagar leem o item, mudam e gravam de volta: dois comandos juntos criariam item repetido ou perderiam um campo. Um por vez. */
|
|
545
566
|
const comTrava = (fn) => withFileLock(path.join(dirOf(d), 'cofre-op.lock'), fn, {
|
|
546
567
|
waitMs: d.lockWaitMs === undefined ? LOCK_WAIT_MS : d.lockWaitMs,
|
|
547
568
|
onTimeout: () => fail('falha', 'Outro comando esta gravando no 1Password agora. Tente de novo em alguns instantes.'),
|
|
548
569
|
});
|
|
549
570
|
|
|
550
|
-
async function run(args, input, secrets) {
|
|
571
|
+
async function run(args, input, secrets, extra = {}) {
|
|
551
572
|
let tk = await token();
|
|
552
573
|
if (!tk) return { erro: semChave() };
|
|
553
|
-
let r = await call(tk, args, input);
|
|
574
|
+
let r = await call(tk, args, input, extra);
|
|
554
575
|
let c = r.ok ? null : classifyOp(d, r, secrets);
|
|
555
576
|
// A variavel do programa pode estar velha: janela aberta com uma chave que depois foi revogada e trocada (a
|
|
556
577
|
// nova esta gravada no computador). Chave RECUSADA vinda da variavel => tenta a gravada, se for outra. So esta
|
|
@@ -558,7 +579,7 @@ function makeOpBackend(d) {
|
|
|
558
579
|
if (c && c.codigo === 'credencial-invalida' && tk === fromEnv()) {
|
|
559
580
|
const gravada = await fromDisk();
|
|
560
581
|
if (gravada && gravada !== tk) {
|
|
561
|
-
const r2 = await call(gravada, args, input);
|
|
582
|
+
const r2 = await call(gravada, args, input, extra);
|
|
562
583
|
tk = gravada;
|
|
563
584
|
r = r2;
|
|
564
585
|
c = r.ok ? null : classifyOp(d, r, secrets);
|
|
@@ -602,13 +623,13 @@ function makeOpBackend(d) {
|
|
|
602
623
|
}
|
|
603
624
|
let w;
|
|
604
625
|
if (!item) {
|
|
605
|
-
w = await
|
|
626
|
+
w = await runComMolde(['item', 'create', '--vault', VAULT_NAME, '--tags', ITEM_TAG], JSON.stringify(itemTemplate(ref, valor)), secrets);
|
|
606
627
|
} else {
|
|
607
628
|
// item que ja existe (pode ser do aluno, com varios campos): muda ou insere SO o campo pedido
|
|
608
629
|
const campo = findField(item.fields, ref.campo);
|
|
609
630
|
if (campo) campo.value = valor;
|
|
610
631
|
else item.fields.push(ref.campo === CREDENTIAL ? { id: CREDENTIAL, type: 'CONCEALED', label: CREDENTIAL, value: valor } : { type: 'CONCEALED', label: ref.campo, value: valor });
|
|
611
|
-
w = await
|
|
632
|
+
w = await runComMolde(['item', 'edit', ref.item, '--vault', VAULT_NAME], JSON.stringify(item), secrets);
|
|
612
633
|
}
|
|
613
634
|
if (w.erro) return w.erro;
|
|
614
635
|
return { ok: true, criado: !item };
|
package/lib/infisical-cli.js
CHANGED
|
@@ -31,7 +31,7 @@ const os = require('os');
|
|
|
31
31
|
const path = require('path');
|
|
32
32
|
const crypto = require('crypto');
|
|
33
33
|
const fs = require('fs');
|
|
34
|
-
const { spawn, spawnSync } = require('child_process');
|
|
34
|
+
const { spawn, spawnSync, execFileSync } = require('child_process');
|
|
35
35
|
|
|
36
36
|
// Versao minima aceita: login por navegador SEM terminal + perfis (--profile/--save-as) so existem a partir daqui
|
|
37
37
|
// (resultado-cli.md, secao 7: "Login por navegador seguro sem TTY: v0.43.139"). O projeto e criado pela API,
|
|
@@ -51,6 +51,7 @@ const LOGOUT_TIMEOUT_MS = 60000;
|
|
|
51
51
|
const EXTRACT_TIMEOUT_MS = 300000;
|
|
52
52
|
const INSTALL_TIMEOUT_MS = 15 * 60 * 1000;
|
|
53
53
|
const DEFAULT_LOGIN_TIMEOUT_MS = 540000;
|
|
54
|
+
const CLIPBOARD_POLL_MS = 2000;
|
|
54
55
|
const DOWNLOAD_TIMEOUT_MS = 15 * 60 * 1000;
|
|
55
56
|
const DOWNLOAD_MAX_BYTES = 400 * 1024 * 1024;
|
|
56
57
|
const OUTPUT_CAP = 16 * 1024 * 1024;
|
|
@@ -351,10 +352,74 @@ function makeDefaultCliDeps(overrides = {}) {
|
|
|
351
352
|
tmpdir: os.tmpdir(),
|
|
352
353
|
run: runProcess,
|
|
353
354
|
download: (url) => defaultDownload(url, process.platform),
|
|
355
|
+
readClipboard: () => readClipboardText(process.platform),
|
|
356
|
+
clearClipboard: () => clearClipboardText(process.platform),
|
|
357
|
+
postLocal: postToLoopback,
|
|
358
|
+
sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
|
|
354
359
|
...overrides,
|
|
355
360
|
};
|
|
356
361
|
}
|
|
357
362
|
|
|
363
|
+
// ─── Reserva do login: o codigo copiado da tela "Unable to reach CLI" ─────────
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Teste real num Mac (07/11/2026): o Safari nao deixa a pagina do Infisical (https) entregar o login ao CLI em
|
|
367
|
+
* http://127.0.0.1:<porta> e mostra "Unable to reach CLI" com o botao "Copy to clipboard". Sem terminal, o CLI nao
|
|
368
|
+
* aceita colar (so le o codigo quando tem TTY). Entao, enquanto o login espera, o Auroq olha a area de transferencia:
|
|
369
|
+
* quando o aluno clica "Copy to clipboard", o codigo (base64 de {JTWToken,email,privateKey}) vai do proprio Auroq para
|
|
370
|
+
* o CLI pelo mesmo endereco local que a pagina usaria, e a area de transferencia e limpa. Nunca mostra nem guarda o
|
|
371
|
+
* codigo; so aceita exatamente esse formato.
|
|
372
|
+
*/
|
|
373
|
+
function readClipboardText(platform) {
|
|
374
|
+
try {
|
|
375
|
+
if (platform === 'darwin') return execFileSync('/usr/bin/pbpaste', [], { encoding: 'utf8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'], maxBuffer: 1024 * 1024 });
|
|
376
|
+
if (platform === 'win32') return execFileSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', 'Get-Clipboard -Raw'], { encoding: 'utf8', timeout: 8000, stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true, maxBuffer: 1024 * 1024 });
|
|
377
|
+
} catch { /* sem area de transferencia: segue esperando o navegador */ }
|
|
378
|
+
return '';
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function clearClipboardText(platform) {
|
|
382
|
+
try {
|
|
383
|
+
if (platform === 'darwin') execFileSync('/usr/bin/pbcopy', [], { input: '', timeout: 5000, stdio: ['pipe', 'ignore', 'ignore'] });
|
|
384
|
+
else if (platform === 'win32') execFileSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', 'Set-Clipboard -Value $null'], { timeout: 8000, stdio: 'ignore', windowsHide: true });
|
|
385
|
+
} catch { /* melhor esforco */ }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** POST JSON para http://127.0.0.1:<porta>/ (o servidor que o proprio CLI abriu para o login). Nunca lanca. */
|
|
389
|
+
function postToLoopback(port, body) {
|
|
390
|
+
return new Promise((resolve) => {
|
|
391
|
+
let req;
|
|
392
|
+
try {
|
|
393
|
+
req = require('http').request({ host: '127.0.0.1', port, path: '/', method: 'POST', timeout: 15000,
|
|
394
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) } }, (res) => {
|
|
395
|
+
res.resume();
|
|
396
|
+
res.on('end', () => resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, status: res.statusCode }));
|
|
397
|
+
});
|
|
398
|
+
} catch { resolve({ ok: false }); return; }
|
|
399
|
+
req.on('timeout', () => req.destroy());
|
|
400
|
+
req.on('error', () => resolve({ ok: false }));
|
|
401
|
+
req.end(body);
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** O texto e o codigo da tela "Unable to reach CLI"? Devolve o JSON a entregar ao CLI, ou null. */
|
|
406
|
+
function parseCopiedLoginToken(text) {
|
|
407
|
+
const t = String(text || '').trim();
|
|
408
|
+
if (t.length < 40 || t.length > 20000 || !/^[A-Za-z0-9+/=]+$/.test(t)) return null;
|
|
409
|
+
let obj;
|
|
410
|
+
try { obj = JSON.parse(Buffer.from(t, 'base64').toString('utf8')); } catch { return null; }
|
|
411
|
+
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return null;
|
|
412
|
+
if (typeof obj.JTWToken !== 'string' || !/^eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(obj.JTWToken)) return null;
|
|
413
|
+
if (typeof obj.email !== 'string' || !obj.email.includes('@')) return null;
|
|
414
|
+
return JSON.stringify({ JTWToken: obj.JTWToken, email: obj.email, privateKey: typeof obj.privateKey === 'string' ? obj.privateKey : '' });
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function callbackPortOf(url) {
|
|
418
|
+
const m = /[?&]callback_port=(\d{2,5})(?:&|$)/.exec(String(url || ''));
|
|
419
|
+
const n = m ? Number(m[1]) : NaN;
|
|
420
|
+
return n > 0 && n < 65536 ? n : null;
|
|
421
|
+
}
|
|
422
|
+
|
|
358
423
|
/** Completa o `d` recebido com os padroes reais (os testes passam so o que querem trocar). */
|
|
359
424
|
function withDefaults(d) {
|
|
360
425
|
const base = makeDefaultCliDeps();
|
|
@@ -784,14 +849,44 @@ async function browserLogin(dIn, cli, { domain, profile = PROFILE, timeoutMs = D
|
|
|
784
849
|
found(extractLoginUrl(buffer));
|
|
785
850
|
};
|
|
786
851
|
|
|
852
|
+
// Reserva (Mac e Windows): o aluno clica "Copy to clipboard" na tela "Unable to reach CLI" e o Auroq entrega.
|
|
853
|
+
let rodando = true;
|
|
854
|
+
let entregue = false;
|
|
855
|
+
const vigiarAreaDeTransferencia = async () => {
|
|
856
|
+
if (d.platform !== 'darwin' && d.platform !== 'win32') return;
|
|
857
|
+
if (typeof d.readClipboard !== 'function' || typeof d.postLocal !== 'function') return;
|
|
858
|
+
while (rodando && !entregue) {
|
|
859
|
+
await d.sleep(CLIPBOARD_POLL_MS);
|
|
860
|
+
if (!rodando) return;
|
|
861
|
+
const port = callbackPortOf(url);
|
|
862
|
+
if (!port) continue;
|
|
863
|
+
let copiado = '';
|
|
864
|
+
let corpo = null;
|
|
865
|
+
try { copiado = String(await d.readClipboard()); corpo = parseCopiedLoginToken(copiado); } catch { corpo = null; }
|
|
866
|
+
if (!corpo) continue;
|
|
867
|
+
const enviado = await d.postLocal(port, corpo);
|
|
868
|
+
if (!(enviado && enviado.ok)) continue; // o CLI nao aceitou: deixa a area de transferencia como estava
|
|
869
|
+
entregue = true;
|
|
870
|
+
// limpa so se ainda for o mesmo codigo (o aluno pode ter copiado outra coisa nesse meio tempo)
|
|
871
|
+
try {
|
|
872
|
+
if (typeof d.clearClipboard === 'function' && String(await d.readClipboard()).trim() === copiado.trim()) await d.clearClipboard();
|
|
873
|
+
} catch { /* melhor esforco */ }
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
const vigia = vigiarAreaDeTransferencia().catch(() => {});
|
|
877
|
+
|
|
787
878
|
let r;
|
|
788
879
|
try {
|
|
789
880
|
r = await d.run(cli, ['login', '--domain', domain, '--save-as', profile, '--silent'], {
|
|
790
881
|
env: cliEnv(d.env), timeoutMs, stdinIgnore: true, onStderr,
|
|
791
882
|
});
|
|
792
883
|
} catch {
|
|
884
|
+
rodando = false;
|
|
793
885
|
return { ok: false, motivo: 'falhou', url, detalhe: 'nao consegui rodar o CLI' };
|
|
886
|
+
} finally {
|
|
887
|
+
rodando = false;
|
|
794
888
|
}
|
|
889
|
+
void vigia; // para sozinho na proxima volta (nao segura o resultado do login)
|
|
795
890
|
r = r || {};
|
|
796
891
|
// `run` sem tempo real (ou saida que chegou toda no fim): olha o texto final
|
|
797
892
|
if (!url) found(extractLoginUrl(`${buffer}\n${r.stderr || ''}\n`, { complete: true }));
|
|
@@ -863,6 +958,8 @@ module.exports = {
|
|
|
863
958
|
runProcess,
|
|
864
959
|
curlDownload,
|
|
865
960
|
extractLoginUrl,
|
|
961
|
+
parseCopiedLoginToken,
|
|
962
|
+
callbackPortOf,
|
|
866
963
|
releaseTarget,
|
|
867
964
|
parseChecksums,
|
|
868
965
|
scrub,
|
package/lib/onepassword.js
CHANGED
|
@@ -552,6 +552,8 @@ const SERVICE_ACCOUNT_NAME = 'Auroq';
|
|
|
552
552
|
// `op service-account create` so existe desde a 2.26.0 e `op whoami` so diz QUEM esta falando (conta de
|
|
553
553
|
// servico ou pessoa) desde a 2.30.0; o teste final precisa dessa resposta, entao o minimo e a 2.30.0.
|
|
554
554
|
const MIN_OP_VERSION = '2.30.0';
|
|
555
|
+
const MAC_DADOS_DE_OUTROS_APPS = 'No Mac: se aparecer a pergunta se o Auroq OS (ou o Terminal) pode acessar dados de outros apps, clique em Permitir. Sem isso o 1Password fica invisivel para o Auroq.';
|
|
556
|
+
const MAC_APP_BUNDLE = 'com.1password.1password'; // o 1Password 8 (o "1Password 7" antigo e com.agilebits.onepassword7)
|
|
555
557
|
const INTEGRATION_URL = 'onepassword://settings/developers'; // abre o app direto em Configuracoes > Desenvolvedor
|
|
556
558
|
const BACKUP_TITLE = 'Auroq OS - token da conta de servico';
|
|
557
559
|
const BACKUP_TAG = 'auroq-os';
|
|
@@ -746,7 +748,7 @@ function enableIntegrationSteps(platform) {
|
|
|
746
748
|
? 'Abra as Configuracoes: no menu de cima do Mac, 1Password > Configuracoes (ou Cmd + virgula). Se eu ja abri a tela de Desenvolvedor pra voce, pule pro passo 3.'
|
|
747
749
|
: 'Abra as Configuracoes: clique no nome da sua conta (canto de cima, a esquerda) > Configuracoes. Se eu ja abri a tela de Desenvolvedor pra voce, pule pro passo 3.';
|
|
748
750
|
const digital = platform === 'darwin'
|
|
749
|
-
? 'Para aprovar com a digital: Configuracoes > Seguranca > "Desbloquear com Touch ID
|
|
751
|
+
? 'Para aprovar com a digital (opcional): Configuracoes > Seguranca > "Desbloquear usando Touch ID" (Desbloquear com Touch ID). Sem Touch ID, a janela do 1Password pede so um clique em "Autorizar". Se o Mac perguntar se o Auroq OS (ou o Terminal) pode acessar dados de outros apps, clique em Permitir.'
|
|
750
752
|
: 'Para aprovar com o Windows Hello: Configuracoes > Seguranca > "Desbloquear com Windows Hello". Sem o Windows Hello ligado a janela de aprovacao pode nem aparecer.';
|
|
751
753
|
return [
|
|
752
754
|
'Abra o app do 1Password, entre na sua conta e deixe o app aberto.',
|
|
@@ -758,15 +760,15 @@ function enableIntegrationSteps(platform) {
|
|
|
758
760
|
|
|
759
761
|
/**
|
|
760
762
|
* Receita curta para ligar a digital (Windows Hello / Touch ID) quando nao esta ligada. A documentacao da integracao
|
|
761
|
-
* manda ligar o Windows Hello no Windows; no Mac o Touch ID e opcional (sem ele
|
|
763
|
+
* manda ligar o Windows Hello no Windows; no Mac o Touch ID e opcional (sem ele a janela pede um clique em Autorizar). A
|
|
762
764
|
* senha da conta 1Password NAO faz esse papel. O codigo nao liga nada disso por ele.
|
|
763
765
|
*/
|
|
764
766
|
function biometricSteps(platform) {
|
|
765
767
|
if (platform === 'darwin') {
|
|
766
768
|
return [
|
|
767
769
|
'No Mac, cadastre a digital: Ajustes do Sistema > Touch ID e Senha > Adicionar digital.',
|
|
768
|
-
'No 1Password: Configuracoes > Seguranca > marque "Desbloquear com Touch ID
|
|
769
|
-
'O Touch ID e opcional:
|
|
770
|
+
'No 1Password: Configuracoes > Seguranca > marque "Desbloquear usando Touch ID" (Desbloquear com Touch ID).',
|
|
771
|
+
'O Touch ID e opcional: sem ele, a janela de aprovacao do 1Password pede so um clique em "Autorizar" (ou a senha do seu usuario do Mac, se voce ligou "Desbloqueie o aplicativo com a senha do Mac").',
|
|
770
772
|
];
|
|
771
773
|
}
|
|
772
774
|
return [
|
|
@@ -854,11 +856,19 @@ function runOpInFreshShell(args) {
|
|
|
854
856
|
function openUrl(url) {
|
|
855
857
|
if (process.env.AUROQ_NAO_ABRIR_APP) return;
|
|
856
858
|
try {
|
|
859
|
+
// Mac: o link onepassword:// pode abrir o "1Password 7" antigo, se ele ainda estiver instalado (teste real num Mac,
|
|
860
|
+
// 07/11/2026). Pede o app atual pelo identificador; se ele nao estiver la, abre do jeito de sempre.
|
|
857
861
|
const [cmd, args] = process.platform === 'darwin'
|
|
858
|
-
? ['open', [url]]
|
|
862
|
+
? ['open', ['-b', MAC_APP_BUNDLE, url]]
|
|
859
863
|
: (process.platform === 'win32' ? ['cmd', ['/c', 'start', '', url]] : ['xdg-open', [url]]);
|
|
860
864
|
const child = spawn(cmd, args, { stdio: 'ignore', detached: true, windowsHide: true, env: opEnv() });
|
|
861
865
|
child.on('error', () => {});
|
|
866
|
+
if (process.platform === 'darwin') {
|
|
867
|
+
child.on('exit', (code) => {
|
|
868
|
+
if (code === 0) return;
|
|
869
|
+
try { const outro = spawn('open', [url], { stdio: 'ignore', detached: true, env: opEnv() }); outro.on('error', () => {}); outro.unref(); } catch { /* receita escrita vale */ }
|
|
870
|
+
});
|
|
871
|
+
}
|
|
862
872
|
child.unref();
|
|
863
873
|
} catch {
|
|
864
874
|
/* sem problema: a receita escrita continua valendo */
|
|
@@ -1091,12 +1101,12 @@ const APP_TEMP_PREFIX = 'auroq-1p-app-';
|
|
|
1091
1101
|
* `finally` nao roda se o processo e morto). So mexe em pasta com esse prefixo e mais velha que `maxAgeMs`. Nunca lanca.
|
|
1092
1102
|
* Devolve quantas apagou.
|
|
1093
1103
|
*/
|
|
1094
|
-
function sweepStaleAppDirs(root = os.tmpdir(), { maxAgeMs = 60 * 60 * 1000, now = Date.now() } = {}) {
|
|
1104
|
+
function sweepStaleAppDirs(root = os.tmpdir(), { maxAgeMs = 60 * 60 * 1000, now = Date.now(), prefix = APP_TEMP_PREFIX } = {}) {
|
|
1095
1105
|
let apagadas = 0;
|
|
1096
1106
|
let nomes = [];
|
|
1097
1107
|
try { nomes = fs.readdirSync(root); } catch { return 0; }
|
|
1098
1108
|
for (const nome of nomes) {
|
|
1099
|
-
if (!nome.startsWith(
|
|
1109
|
+
if (!nome.startsWith(prefix)) continue;
|
|
1100
1110
|
const full = path.join(root, nome);
|
|
1101
1111
|
try {
|
|
1102
1112
|
const st = fs.lstatSync(full);
|
|
@@ -1424,11 +1434,30 @@ function makeProgress(d) {
|
|
|
1424
1434
|
};
|
|
1425
1435
|
}
|
|
1426
1436
|
|
|
1437
|
+
/**
|
|
1438
|
+
* Mac: zera a decisao "acessar dados de outros apps" (TCC, servico SystemPolicyAppData) do programa que abriu este
|
|
1439
|
+
* comando (o app Auroq OS ou o Terminal), para a pergunta do Mac voltar. Teste real (07/11/2026): o `op` le a pasta do
|
|
1440
|
+
* 1Password, o Mac pergunta se o Auroq OS pode acessar dados de outros apps e, se a resposta foi "nao" (ou a pergunta
|
|
1441
|
+
* foi cancelada), fica "nao" para sempre e calado: o `op` so ve "nenhuma conta" e o aluno ouvia "ligue a integracao" em
|
|
1442
|
+
* laco. Zerar so faz o Mac perguntar de novo (nao libera nada sozinho). Nunca lanca; true se zerou.
|
|
1443
|
+
*/
|
|
1444
|
+
function resetMacAppData(env = process.env, run = spawnSync) {
|
|
1445
|
+
const bundle = String(env.__CFBundleIdentifier || '');
|
|
1446
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9.-]{2,200}$/.test(bundle)) return false;
|
|
1447
|
+
try {
|
|
1448
|
+
const r = run('/usr/bin/tccutil', ['reset', 'SystemPolicyAppData', bundle], { stdio: 'ignore', timeout: 15000 });
|
|
1449
|
+
return Boolean(r && !r.error && r.status === 0);
|
|
1450
|
+
} catch {
|
|
1451
|
+
return false;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1427
1455
|
function makeDefaultDeps() {
|
|
1428
1456
|
return {
|
|
1429
1457
|
platform: process.platform,
|
|
1430
1458
|
openUrl,
|
|
1431
1459
|
refreshPath,
|
|
1460
|
+
resetAppData: () => (process.platform === 'darwin' ? resetMacAppData() : false),
|
|
1432
1461
|
appInstalled: () => appInstalled(),
|
|
1433
1462
|
lock: makeLock(),
|
|
1434
1463
|
state: { read: readState, write: writeState },
|
|
@@ -1544,12 +1573,9 @@ function saveBackup(d, account, token) {
|
|
|
1544
1573
|
// conforme o plano (e pode vir traduzido), por isso nunca se usa o nome.
|
|
1545
1574
|
const body = JSON.stringify(backupItemTemplate(token));
|
|
1546
1575
|
const common = ['--tags', BACKUP_TAG, '--account', accountKey(account), '--format', 'json'];
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
}
|
|
1551
|
-
// Windows: o `op item create -` por pipe falha no PowerShell 5.1 ("invalid JSON in piped input", teste real de 27/10),
|
|
1552
|
-
// entao o molde vai num arquivo temporario (UTF-8 sem BOM) so deste usuario, que o `op` le com --template. O token
|
|
1576
|
+
// Todos os sistemas: o molde vai num arquivo temporario. Por pipe, o `op item create -` falha no PowerShell 5.1
|
|
1577
|
+
// ("invalid JSON in piped input", teste real de 27/10) e, no 1Password CLI 2.41, tambem no Mac ("provide the item
|
|
1578
|
+
// category with '--category' flag", teste real de 07/11/2026). O molde vai num arquivo temporario (UTF-8 sem BOM) so deste usuario, que o `op` le com --template. O token
|
|
1553
1579
|
// continua fora de argumento e de log; o arquivo e apagado em seguida, aconteca o que acontecer. O `op` roda com o
|
|
1554
1580
|
// stdin desligado (`noStdin`): com `--template` ele nao aceita nenhum pipe, nem vazio.
|
|
1555
1581
|
let tmp = null;
|
|
@@ -1571,8 +1597,15 @@ function saveBackup(d, account, token) {
|
|
|
1571
1597
|
* (%TEMP% do perfil, que so ele, o SYSTEM e os administradores leem; o modo 0600 vale no Mac e no Linux e e ignorado no
|
|
1572
1598
|
* Windows). UTF-8 SEM BOM: o BOM faria o `op` recusar o JSON. Devolve { dir, file }; quem chama apaga a pasta.
|
|
1573
1599
|
*/
|
|
1600
|
+
const MOLDE_PREFIX = 'auroq-molde-';
|
|
1601
|
+
|
|
1602
|
+
/**
|
|
1603
|
+
* Molde do item (com o valor) num arquivo temporario so do usuario. Antes, apaga moldes de execucoes anteriores que
|
|
1604
|
+
* morreram no meio (Ctrl+C ou janela fechada nao deixam o `finally` rodar) e que tenham mais de 10 minutos.
|
|
1605
|
+
*/
|
|
1574
1606
|
function writeTemplateFile(content) {
|
|
1575
|
-
|
|
1607
|
+
try { sweepStaleAppDirs(os.tmpdir(), { prefix: MOLDE_PREFIX, maxAgeMs: 10 * 60 * 1000 }); } catch { /* faxina e extra */ }
|
|
1608
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), MOLDE_PREFIX));
|
|
1576
1609
|
const file = path.join(dir, 'molde.json');
|
|
1577
1610
|
try {
|
|
1578
1611
|
fs.writeFileSync(file, Buffer.from(content, 'utf8'), { flag: 'wx', mode: 0o600 });
|
|
@@ -1812,6 +1845,11 @@ async function runConnect(opts, d, prog) {
|
|
|
1812
1845
|
prog.reset('app');
|
|
1813
1846
|
return fim('aguardando', 'instalar-app', 'Nao achei o app do 1Password neste computador. Instale com: npx -y auroq-os@latest conectar-1password --instalar-app --agente (ou baixe em https://1password.com/downloads). Se ele ja esta instalado num lugar fora do comum, abra o app, entre na sua conta e ligue "Integrar com a CLI do 1Password" em Configuracoes > Desenvolvedor; depois rode de novo.');
|
|
1814
1847
|
}
|
|
1848
|
+
if (!accounts.length && d.platform === 'darwin' && typeof d.resetAppData === 'function' && d.resetAppData()) {
|
|
1849
|
+
// a conta pode estar escondida pela protecao "dados de outros apps" do Mac: a pergunta volta e o aluno permite
|
|
1850
|
+
out.log(`${BOLD}${MAC_DADOS_DE_OUTROS_APPS}${RESET}`);
|
|
1851
|
+
accounts = listAccounts(d);
|
|
1852
|
+
}
|
|
1815
1853
|
if (!accounts.length) {
|
|
1816
1854
|
showIntegrationHelp(d, out);
|
|
1817
1855
|
if (waitSeconds > 0) {
|
|
@@ -1826,7 +1864,7 @@ async function runConnect(opts, d, prog) {
|
|
|
1826
1864
|
}
|
|
1827
1865
|
if (!accounts.length) {
|
|
1828
1866
|
prog.reset('app');
|
|
1829
|
-
return fim('aguardando', 'ligar-integracao',
|
|
1867
|
+
return fim('aguardando', 'ligar-integracao', `Falta ligar "Integrate with 1Password CLI" nas configuracoes do app do 1Password (Configuracoes > Desenvolvedor). Depois e so rodar de novo.${d.platform === 'darwin' ? ` ${MAC_DADOS_DE_OUTROS_APPS}` : ''}`);
|
|
1830
1868
|
}
|
|
1831
1869
|
}
|
|
1832
1870
|
prog.mark('conta', 'app');
|
|
@@ -2198,6 +2236,7 @@ module.exports = {
|
|
|
2198
2236
|
refreshPath,
|
|
2199
2237
|
installOpDirect,
|
|
2200
2238
|
installMacAppDirect,
|
|
2239
|
+
resetMacAppData,
|
|
2201
2240
|
auroqOpBin,
|
|
2202
2241
|
OP_DIRETO,
|
|
2203
2242
|
runOp,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"algorithm": "sha256",
|
|
4
4
|
"scope": "packaged-runtime-and-cascas",
|
|
5
|
-
"version": "2.8.
|
|
5
|
+
"version": "2.8.10",
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": ".auroq-core/constitution.md",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"path": ".auroq-core/core-config.yaml",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "11f011d4d20d781521606c4d0f2625ebf6bee36861ca2056697c9d73cd30fd2f"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": ".auroq-core/core/synapse/context/context-builder.js",
|
|
@@ -254,7 +254,7 @@
|
|
|
254
254
|
},
|
|
255
255
|
{
|
|
256
256
|
"path": "lib/cofre.js",
|
|
257
|
-
"sha256": "
|
|
257
|
+
"sha256": "c3648b80ad72df055726571aa107608489808287d557386625fd8157f9f6279f"
|
|
258
258
|
},
|
|
259
259
|
{
|
|
260
260
|
"path": "lib/credentials.js",
|
|
@@ -270,7 +270,7 @@
|
|
|
270
270
|
},
|
|
271
271
|
{
|
|
272
272
|
"path": "lib/infisical-cli.js",
|
|
273
|
-
"sha256": "
|
|
273
|
+
"sha256": "6ebd63594fedb7a3b0bee58b70a2ce1b070d91c9dc20fd6495abaab35c8b84af"
|
|
274
274
|
},
|
|
275
275
|
{
|
|
276
276
|
"path": "lib/infisical.js",
|
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
},
|
|
283
283
|
{
|
|
284
284
|
"path": "lib/onepassword.js",
|
|
285
|
-
"sha256": "
|
|
285
|
+
"sha256": "eb54a524ad488c79577be06ea7496e421660f9e4dbc8fce3b843124b893f0780"
|
|
286
286
|
},
|
|
287
287
|
{
|
|
288
288
|
"path": "lib/supabase.js",
|
|
@@ -298,7 +298,7 @@
|
|
|
298
298
|
},
|
|
299
299
|
{
|
|
300
300
|
"path": "package.json",
|
|
301
|
-
"sha256": "
|
|
301
|
+
"sha256": "f78cae244b3efba3bd354a6efbd0805bb761f2d6acece93426dfd0b02bbc7b0f"
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
"path": "scripts/build-pack.mjs",
|