1use std::collections::BTreeSet;
14use std::path::{Path, PathBuf};
15
16use clap::{Args, Subcommand};
17use serde::Serialize;
18
19use crate::cli::lifecycle::leak;
20use zad::config::{self, OnePassServiceCfg};
21use zad::error::{Result, ZadError};
22use zad::secrets::{self, Scope};
23use zad::service::onepass::client::{
24 CreateItemRequest, Item, ItemSummary, ListItemsFilter, OnePassClient, ParsedOpRef, Vault,
25 parse_op_ref, scan_op_refs,
26};
27use zad::service::onepass::permissions::{self as perms, EffectivePermissions, OnePassFunction};
28
29#[derive(Debug, Args)]
34pub struct OnePassArgs {
35 #[command(subcommand)]
36 pub action: Action,
37}
38
39#[derive(Debug, Subcommand)]
40pub enum Action {
41 Vaults(VaultsArgs),
43 Items(ItemsArgs),
45 Tags(TagsArgs),
47 Get(GetArgs),
50 Read(ReadArgs),
52 Inject(InjectArgs),
56 Create(CreateItemArgs),
59 Whoami(WhoamiArgs),
61 Permissions(PermissionsArgs),
63}
64
65#[derive(Debug, Args)]
66pub struct VaultsArgs {
67 #[arg(long)]
68 pub json: bool,
69}
70
71#[derive(Debug, Args)]
72pub struct ItemsArgs {
73 #[arg(long)]
75 pub vault: Option<String>,
76 #[arg(long = "tag")]
78 pub tags: Vec<String>,
79 #[arg(long = "category")]
81 pub categories: Vec<String>,
82 #[arg(long)]
83 pub json: bool,
84}
85
86#[derive(Debug, Args)]
87pub struct TagsArgs {
88 #[arg(long)]
89 pub json: bool,
90}
91
92#[derive(Debug, Args)]
93pub struct GetArgs {
94 pub item: String,
96 #[arg(long)]
97 pub vault: Option<String>,
98 #[arg(long)]
99 pub json: bool,
100}
101
102#[derive(Debug, Args)]
103pub struct ReadArgs {
104 pub reference: String,
106 #[arg(long)]
107 pub json: bool,
108}
109
110#[derive(Debug, Args)]
111pub struct InjectArgs {
112 #[arg(long = "in", default_value = "-")]
114 pub input: String,
115 #[arg(long = "out")]
117 pub output: Option<String>,
118 #[arg(long)]
119 pub json: bool,
120}
121
122#[derive(Debug, Args)]
123pub struct CreateItemArgs {
124 #[arg(long)]
125 pub title: String,
126 #[arg(long)]
127 pub vault: String,
128 #[arg(long, default_value = "Login")]
129 pub category: String,
130 #[arg(long = "tag")]
133 pub tags: Vec<String>,
134 #[arg(long = "field")]
138 pub fields: Vec<String>,
139 #[arg(long)]
140 pub json: bool,
141}
142
143#[derive(Debug, Args)]
144pub struct WhoamiArgs {
145 #[arg(long)]
146 pub json: bool,
147}
148
149#[derive(Debug, Args)]
154pub struct PermissionsArgs {
155 #[command(subcommand)]
156 pub action: Option<PermissionsAction>,
157 #[arg(long)]
158 pub json: bool,
159}
160
161#[derive(Debug, Subcommand)]
162#[allow(clippy::large_enum_variant)]
163pub enum PermissionsAction {
164 Show(PermissionsShowArgs),
166 Path(PermissionsPathArgs),
168 Init(PermissionsInitArgs),
170 Check(PermissionsCheckArgs),
172 #[command(flatten)]
175 Staging(crate::cli::permissions::StagingAction),
176}
177
178#[derive(Debug, Args)]
179pub struct PermissionsShowArgs {
180 #[arg(long)]
181 pub json: bool,
182}
183
184#[derive(Debug, Args)]
185pub struct PermissionsPathArgs {
186 #[arg(long)]
187 pub json: bool,
188}
189
190#[derive(Debug, Args)]
191pub struct PermissionsInitArgs {
192 #[arg(long)]
193 pub local: bool,
194 #[arg(long)]
195 pub force: bool,
196 #[arg(long)]
197 pub json: bool,
198}
199
200#[derive(Debug, Args)]
201pub struct PermissionsCheckArgs {
202 #[arg(long)]
204 pub function: String,
205 #[arg(long)]
206 pub vault: Option<String>,
207 #[arg(long)]
208 pub item: Option<String>,
209 #[arg(long = "tag")]
210 pub tags: Vec<String>,
211 #[arg(long)]
212 pub category: Option<String>,
213 #[arg(long)]
214 pub field: Option<String>,
215 #[arg(long)]
216 pub title: Option<String>,
217 #[arg(long)]
218 pub reference: Option<String>,
219 #[arg(long)]
220 pub json: bool,
221}
222
223pub async fn run(args: OnePassArgs) -> Result<()> {
228 match args.action {
229 Action::Vaults(a) => run_vaults(a).await,
230 Action::Items(a) => run_items(a).await,
231 Action::Tags(a) => run_tags(a).await,
232 Action::Get(a) => run_get(a).await,
233 Action::Read(a) => run_read(a).await,
234 Action::Inject(a) => run_inject(a).await,
235 Action::Create(a) => run_create(a).await,
236 Action::Whoami(a) => run_whoami(a).await,
237 Action::Permissions(a) => run_permissions(a),
238 }
239}
240
241async fn run_vaults(args: VaultsArgs) -> Result<()> {
246 let client = client_for(&["read"])?;
247 let permissions = perms::load_effective()?;
248 permissions.check_time(OnePassFunction::Vaults)?;
249
250 let vaults = client.list_vaults().await?;
251 let visible = permissions.filter_vaults(vaults);
252
253 if args.json {
254 println!("{}", serde_json::to_string_pretty(&visible).unwrap());
255 return Ok(());
256 }
257 if visible.is_empty() {
258 println!("(no vaults visible to this account)");
259 return Ok(());
260 }
261 for v in &visible {
262 println!("{}\t{}", v.id, v.name);
263 }
264 Ok(())
265}
266
267async fn run_items(args: ItemsArgs) -> Result<()> {
268 let client = client_for(&["read"])?;
269 let permissions = perms::load_effective()?;
270 permissions.check_time(OnePassFunction::Items)?;
271
272 let filter = ListItemsFilter {
273 vault: args.vault.clone(),
274 tags: args.tags.clone(),
275 categories: args.categories.clone(),
276 };
277 let items = client.list_items(&filter).await?;
278 let visible = permissions.filter_items(items);
279
280 if args.json {
281 println!("{}", serde_json::to_string_pretty(&visible).unwrap());
282 return Ok(());
283 }
284 if visible.is_empty() {
285 println!("(no items match)");
286 return Ok(());
287 }
288 for it in &visible {
289 let tags = if it.tags.is_empty() {
290 String::new()
291 } else {
292 format!(" [{}]", it.tags.join(","))
293 };
294 println!(
295 "{}\t{}\t{}\t{}{tags}",
296 it.id, it.vault.name, it.category, it.title
297 );
298 }
299 Ok(())
300}
301
302async fn run_tags(args: TagsArgs) -> Result<()> {
303 let client = client_for(&["read"])?;
304 let permissions = perms::load_effective()?;
305 permissions.check_time(OnePassFunction::Tags)?;
306
307 let items = client.list_items(&ListItemsFilter::default()).await?;
308 let visible_items = permissions.filter_items(items);
309 let tags = permissions.filter_tags(&visible_items);
310
311 if args.json {
312 println!("{}", serde_json::to_string_pretty(&tags).unwrap());
313 return Ok(());
314 }
315 if tags.is_empty() {
316 println!("(no tags visible)");
317 return Ok(());
318 }
319 for t in &tags {
320 println!("{t}");
321 }
322 Ok(())
323}
324
325async fn run_get(args: GetArgs) -> Result<()> {
326 let client = client_for(&["read"])?;
327 let permissions = perms::load_effective()?;
328 permissions.check_time(OnePassFunction::Get)?;
329
330 let vault = args.vault.clone().or_else(|| {
331 effective_config()
332 .ok()
333 .and_then(|(c, _, _, _)| c.default_vault)
334 });
335 let item = client.get_item(&args.item, vault.as_deref()).await?;
336 permissions.check_get(&args.item, &item)?;
337 let filtered = permissions.filter_fields(item);
338
339 if args.json {
340 println!("{}", serde_json::to_string_pretty(&filtered).unwrap());
341 return Ok(());
342 }
343 println!("id : {}", filtered.id);
344 println!("title : {}", filtered.title);
345 println!("category : {}", filtered.category);
346 println!("vault : {} ({})", filtered.vault.name, filtered.vault.id);
347 if !filtered.tags.is_empty() {
348 println!("tags : {}", filtered.tags.join(", "));
349 }
350 if !filtered.fields.is_empty() {
351 println!("fields :");
352 for f in &filtered.fields {
353 let value_marker = if f.value.is_some() {
354 ""
355 } else {
356 " (value hidden)"
357 };
358 println!(
359 " - {label} [{ftype}]{marker}",
360 label = if f.label.is_empty() {
361 f.id.as_str()
362 } else {
363 f.label.as_str()
364 },
365 ftype = f.field_type,
366 marker = value_marker
367 );
368 }
369 }
370 Ok(())
371}
372
373async fn run_read(args: ReadArgs) -> Result<()> {
374 let client = client_for(&["read"])?;
375 let permissions = perms::load_effective()?;
376 permissions.check_time(OnePassFunction::Read)?;
377
378 let parsed = parse_op_ref(&args.reference)?;
379 let item = client
382 .get_item(&parsed.item, Some(parsed.vault.as_str()))
383 .await?;
384 permissions.check_read(&args.reference, &item, &parsed.field)?;
385
386 let value = client.read(&args.reference).await?;
387
388 if args.json {
389 let out = serde_json::json!({
390 "command": "1pass.read",
391 "reference": args.reference,
392 "value": value,
393 });
394 println!("{}", serde_json::to_string_pretty(&out).unwrap());
395 return Ok(());
396 }
397 println!("{value}");
400 Ok(())
401}
402
403async fn run_inject(args: InjectArgs) -> Result<()> {
404 let client = client_for(&["read"])?;
405 let permissions = perms::load_effective()?;
406 permissions.check_time(OnePassFunction::Inject)?;
407
408 let template = read_input(&args.input)?;
409 let refs = scan_op_refs(&template);
412 for r in &refs {
413 permissions.check_inject_ref(r)?;
414 }
415
416 let rendered = client.inject(&template).await?;
417 permissions.check_inject_body(&rendered)?;
418
419 match args.output.as_deref() {
420 Some(p) => {
421 std::fs::write(p, &rendered).map_err(|e| ZadError::Io {
422 path: PathBuf::from(p),
423 source: e,
424 })?;
425 }
426 None => {
427 if args.json {
428 let out = serde_json::json!({
429 "command": "1pass.inject",
430 "rendered": rendered,
431 "refs": refs.iter().map(|r| &r.source).collect::<Vec<_>>(),
432 });
433 println!("{}", serde_json::to_string_pretty(&out).unwrap());
434 return Ok(());
435 }
436 print!("{rendered}");
437 }
438 }
439 Ok(())
440}
441
442async fn run_create(args: CreateItemArgs) -> Result<()> {
443 let client = client_for(&["write"])?;
444 let permissions = perms::load_effective()?;
445 permissions.check_create(&args.vault, &args.category, &args.title, &args.tags)?;
446
447 let req = CreateItemRequest {
448 title: args.title.clone(),
449 vault: args.vault.clone(),
450 category: args.category.clone(),
451 tags: args.tags.iter().cloned().collect::<BTreeSet<_>>(),
452 fields: args.fields.clone(),
453 };
454 let created = client.create_item(&req).await?;
455
456 if args.json {
457 println!("{}", serde_json::to_string_pretty(&created).unwrap());
458 return Ok(());
459 }
460 println!(
461 "created: {} ({}) in {}",
462 created.title, created.id, created.vault.name
463 );
464 Ok(())
465}
466
467async fn run_whoami(args: WhoamiArgs) -> Result<()> {
468 let client = client_for(&[])?;
470 let me = client.whoami().await?;
471 if args.json {
472 println!("{}", serde_json::to_string_pretty(&me).unwrap());
473 return Ok(());
474 }
475 if !me.url.is_empty() {
476 println!("url : {}", me.url);
477 }
478 if !me.service_account_type.is_empty() {
479 println!("account_type : {}", me.service_account_type);
480 }
481 if !me.user_uuid.is_empty() {
482 println!("user_uuid : {}", me.user_uuid);
483 }
484 if !me.account_uuid.is_empty() {
485 println!("account_uuid : {}", me.account_uuid);
486 }
487 Ok(())
488}
489
490fn run_permissions(args: PermissionsArgs) -> Result<()> {
495 match args.action {
496 None => run_permissions_show(PermissionsShowArgs { json: args.json }),
497 Some(PermissionsAction::Show(a)) => run_permissions_show(a),
498 Some(PermissionsAction::Path(a)) => run_permissions_path(a),
499 Some(PermissionsAction::Init(a)) => run_permissions_init(a),
500 Some(PermissionsAction::Check(a)) => run_permissions_check(a),
501 Some(PermissionsAction::Staging(a)) => {
502 crate::cli::permissions::run::<perms::PermissionsService>(a)
503 }
504 }
505}
506
507#[derive(Debug, Serialize)]
508struct PermissionsScopeOut {
509 path: String,
510 present: bool,
511}
512
513#[derive(Debug, Serialize)]
514struct PermissionsShowOut {
515 command: &'static str,
516 global: PermissionsScopeOut,
517 local: PermissionsScopeOut,
518}
519
520fn run_permissions_show(args: PermissionsShowArgs) -> Result<()> {
521 let global_path = perms::global_path()?;
522 let local_path = perms::local_path_current()?;
523 let _ = perms::load_effective()?;
524
525 if args.json {
526 let out = PermissionsShowOut {
527 command: "1pass.permissions.show",
528 global: PermissionsScopeOut {
529 path: global_path.display().to_string(),
530 present: global_path.exists(),
531 },
532 local: PermissionsScopeOut {
533 path: local_path.display().to_string(),
534 present: local_path.exists(),
535 },
536 };
537 println!("{}", serde_json::to_string_pretty(&out).unwrap());
538 return Ok(());
539 }
540 println!("1Password permissions");
541 print_scope_block("global", &global_path);
542 print_scope_block("local", &local_path);
543 Ok(())
544}
545
546fn print_scope_block(label: &str, path: &Path) {
547 println!();
548 println!(" [{label}] {}", path.display());
549 if !path.exists() {
550 println!(" status : not present (no restrictions from this scope)");
551 return;
552 }
553 match std::fs::read_to_string(path) {
554 Ok(body) => {
555 for line in body.lines() {
556 println!(" {line}");
557 }
558 }
559 Err(e) => println!(" status : read error — {e}"),
560 }
561}
562
563#[derive(Debug, Serialize)]
564struct PermissionsPathOut {
565 command: &'static str,
566 global: String,
567 local: String,
568}
569
570fn run_permissions_path(args: PermissionsPathArgs) -> Result<()> {
571 let global_path = perms::global_path()?;
572 let local_path = perms::local_path_current()?;
573 if args.json {
574 let out = PermissionsPathOut {
575 command: "1pass.permissions.path",
576 global: global_path.display().to_string(),
577 local: local_path.display().to_string(),
578 };
579 println!("{}", serde_json::to_string_pretty(&out).unwrap());
580 return Ok(());
581 }
582 println!("{}", global_path.display());
583 println!("{}", local_path.display());
584 Ok(())
585}
586
587#[derive(Debug, Serialize)]
588struct PermissionsInitOut {
589 command: &'static str,
590 scope: &'static str,
591 path: String,
592 written: bool,
593}
594
595fn run_permissions_init(args: PermissionsInitArgs) -> Result<()> {
596 let (path, scope_label): (PathBuf, &'static str) = if args.local {
597 (perms::local_path_current()?, "local")
598 } else {
599 (perms::global_path()?, "global")
600 };
601 if path.exists() && !args.force {
602 return Err(ZadError::Invalid(format!(
603 "{} already exists — pass --force to overwrite",
604 path.display()
605 )));
606 }
607 let key = zad::permissions::signing::load_or_create_from_keychain()?;
608 zad::permissions::signing::write_public_key_cache(&key)?;
609 perms::save_file(&path, &perms::starter_template(), &key)?;
610 if args.json {
611 let out = PermissionsInitOut {
612 command: "1pass.permissions.init",
613 scope: scope_label,
614 path: path.display().to_string(),
615 written: true,
616 };
617 println!("{}", serde_json::to_string_pretty(&out).unwrap());
618 return Ok(());
619 }
620 println!(
621 "Wrote 1pass permissions starter policy to {} ({scope_label}).",
622 path.display()
623 );
624 println!("Signed with key {}.", key.fingerprint());
625 println!("Edit to narrow further; re-run `zad 1pass permissions show` to inspect.");
626 Ok(())
627}
628
629#[derive(Debug, Serialize)]
630struct PermissionsCheckOut {
631 command: &'static str,
632 function: String,
633 allowed: bool,
634 #[serde(skip_serializing_if = "Option::is_none")]
635 reason: Option<String>,
636 #[serde(skip_serializing_if = "Option::is_none")]
637 config_path: Option<String>,
638}
639
640fn run_permissions_check(args: PermissionsCheckArgs) -> Result<()> {
641 let permissions = perms::load_effective()?;
642 let outcome = check_hypothetical(&permissions, &args);
643 emit_check_result(&args, outcome)
644}
645
646fn emit_check_result(args: &PermissionsCheckArgs, outcome: Result<()>) -> Result<()> {
647 match outcome {
648 Ok(()) => {
649 if args.json {
650 let out = PermissionsCheckOut {
651 command: "1pass.permissions.check",
652 function: args.function.clone(),
653 allowed: true,
654 reason: None,
655 config_path: None,
656 };
657 println!("{}", serde_json::to_string_pretty(&out).unwrap());
658 } else {
659 println!("allowed");
660 }
661 Ok(())
662 }
663 Err(ZadError::PermissionDenied {
664 function,
665 reason,
666 config_path,
667 }) => {
668 if args.json {
669 let out = PermissionsCheckOut {
670 command: "1pass.permissions.check",
671 function: function.to_string(),
672 allowed: false,
673 reason: Some(reason.clone()),
674 config_path: Some(config_path.display().to_string()),
675 };
676 println!("{}", serde_json::to_string_pretty(&out).unwrap());
677 } else {
678 println!("denied: {reason}");
679 println!(" edit: {}", config_path.display());
680 }
681 std::process::exit(1);
682 }
683 Err(ZadError::Service {
684 name: "1pass",
685 message,
686 }) => {
687 if args.json {
692 let out = PermissionsCheckOut {
693 command: "1pass.permissions.check",
694 function: args.function.clone(),
695 allowed: false,
696 reason: Some(format!("hidden: {message}")),
697 config_path: None,
698 };
699 println!("{}", serde_json::to_string_pretty(&out).unwrap());
700 } else {
701 println!("denied (hidden): {message}");
702 }
703 std::process::exit(1);
704 }
705 Err(other) => Err(other),
706 }
707}
708
709fn check_hypothetical(
710 permissions: &EffectivePermissions,
711 args: &PermissionsCheckArgs,
712) -> Result<()> {
713 if args.function == "create" {
715 let vault = args
716 .vault
717 .as_deref()
718 .ok_or_else(|| ZadError::Invalid("--vault is required for create".into()))?;
719 let category = args.category.as_deref().unwrap_or("Login");
720 let title = args.title.as_deref().unwrap_or("");
721 return permissions.check_create(vault, category, title, &args.tags);
722 }
723
724 let func = OnePassFunction::parse(&args.function)?;
725 permissions.check_time(func)?;
726
727 if args.item.is_some()
730 || args.vault.is_some()
731 || !args.tags.is_empty()
732 || args.category.is_some()
733 {
734 let item = synthetic_item(args);
735 match func {
736 OnePassFunction::Get | OnePassFunction::Read => {
737 permissions.check_get(
738 args.item
739 .as_deref()
740 .or(args.reference.as_deref())
741 .unwrap_or(""),
742 &item,
743 )?;
744 }
745 _ => {
746 let vec = vec![summarize(&item)];
749 if permissions.filter_items(vec).is_empty() {
750 return Err(ZadError::Service {
751 name: "1pass",
752 message: "item is hidden at this scope".into(),
753 });
754 }
755 }
756 }
757 }
758
759 if func == OnePassFunction::Read {
760 if let Some(r) = args.reference.as_deref() {
761 let parsed = parse_op_ref(r)?;
762 let item = synthetic_item_for_ref(&parsed, args);
763 permissions.check_read(r, &item, &parsed.field)?;
764 }
765 }
766 if func == OnePassFunction::Inject {
767 if let Some(r) = args.reference.as_deref() {
768 let parsed = parse_op_ref(r)?;
769 permissions.check_inject_ref(&parsed)?;
770 }
771 }
772 Ok(())
773}
774
775fn synthetic_item(args: &PermissionsCheckArgs) -> Item {
776 Item {
777 id: args.item.clone().unwrap_or_default(),
778 title: args.item.clone().unwrap_or_default(),
779 category: args.category.clone().unwrap_or_default(),
780 tags: args.tags.clone(),
781 vault: zad::service::onepass::client::VaultRef {
782 id: args.vault.clone().unwrap_or_default(),
783 name: args.vault.clone().unwrap_or_default(),
784 },
785 fields: args
786 .field
787 .as_ref()
788 .map(|f| {
789 vec![zad::service::onepass::client::ItemField {
790 id: f.clone(),
791 label: f.clone(),
792 field_type: String::new(),
793 purpose: None,
794 value: None,
795 section: None,
796 }]
797 })
798 .unwrap_or_default(),
799 sections: vec![],
800 updated_at: None,
801 created_at: None,
802 }
803}
804
805fn synthetic_item_for_ref(r: &ParsedOpRef, args: &PermissionsCheckArgs) -> Item {
806 Item {
807 id: r.item.clone(),
808 title: r.item.clone(),
809 category: args.category.clone().unwrap_or_default(),
810 tags: args.tags.clone(),
811 vault: zad::service::onepass::client::VaultRef {
812 id: r.vault.clone(),
813 name: r.vault.clone(),
814 },
815 fields: vec![zad::service::onepass::client::ItemField {
816 id: r.field.clone(),
817 label: r.field.clone(),
818 field_type: String::new(),
819 purpose: None,
820 value: None,
821 section: None,
822 }],
823 sections: vec![],
824 updated_at: None,
825 created_at: None,
826 }
827}
828
829fn summarize(item: &Item) -> ItemSummary {
830 ItemSummary {
831 id: item.id.clone(),
832 title: item.title.clone(),
833 category: item.category.clone(),
834 tags: item.tags.clone(),
835 vault: item.vault.clone(),
836 updated_at: None,
837 created_at: None,
838 }
839}
840
841pub(crate) fn effective_config()
848-> Result<(OnePassServiceCfg, &'static str, Scope<'static>, PathBuf)> {
849 let slug = config::path::project_slug()?;
850 let local_path = config::path::project_service_config_path_for(&slug, "1pass")?;
851 let global_path = config::path::global_service_config_path("1pass")?;
852
853 let project_cfg = config::load()?;
854 if !project_cfg.has_service("1pass") {
855 return Err(ZadError::Invalid(format!(
856 "1pass is not enabled for this project ({}). Run `zad service enable 1pass` first.",
857 config::path::project_config_path()?.display()
858 )));
859 }
860
861 if let Some(cfg) = config::load_flat::<OnePassServiceCfg>(&local_path)? {
862 let slug_leaked = leak(slug);
863 return Ok((cfg, "local", Scope::Project(slug_leaked), local_path));
864 }
865 if let Some(cfg) = config::load_flat::<OnePassServiceCfg>(&global_path)? {
866 return Ok((cfg, "global", Scope::Global, global_path));
867 }
868 Err(ZadError::Invalid(format!(
869 "no 1pass credentials found.\n looked in:\n {}\n {}\n Run `zad service create 1pass`.",
870 local_path.display(),
871 global_path.display()
872 )))
873}
874
875fn client_for(required_scopes: &[&'static str]) -> Result<OnePassClient> {
879 let (cfg, _label, scope, path) = effective_config()?;
880 for s in required_scopes {
881 if !cfg.scopes.iter().any(|x| x == s) {
882 return Err(ZadError::ScopeDenied {
883 service: "1pass",
884 scope: s,
885 config_path: path.clone(),
886 });
887 }
888 }
889 let token = secrets::load(&secrets::account("1pass", "service-account", scope))?.ok_or(
890 ZadError::Service {
891 name: "1pass",
892 message:
893 "service-account token missing from keychain; re-run `zad service create 1pass`"
894 .into(),
895 },
896 )?;
897 Ok(OnePassClient::new(token, cfg.account))
898}
899
900fn read_input(input: &str) -> Result<String> {
902 if input == "-" {
903 use std::io::Read;
904 let mut buf = String::new();
905 std::io::stdin()
906 .read_to_string(&mut buf)
907 .map_err(|e| ZadError::Io {
908 path: PathBuf::from("<stdin>"),
909 source: e,
910 })?;
911 return Ok(buf);
912 }
913 std::fs::read_to_string(input).map_err(|e| ZadError::Io {
914 path: PathBuf::from(input),
915 source: e,
916 })
917}
918
919#[allow(dead_code)]
922fn _type_anchors() -> (Vault,) {
923 (Vault {
924 id: String::new(),
925 name: String::new(),
926 content_version: None,
927 },)
928}