async_nats/auth_utils.rs
1// Copyright 2020-2022 The NATS Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14use nkeys::KeyPair;
15use once_cell::sync::Lazy;
16use regex::Regex;
17use std::{io, path::Path};
18
19/// Loads user credentials file with jwt and key. Return file contents.
20/// Uses tokio non-blocking io
21pub(crate) async fn load_creds(path: &Path) -> io::Result<String> {
22 tokio::fs::read_to_string(path).await.map_err(|err| {
23 io::Error::new(
24 io::ErrorKind::Other,
25 format!("loading creds file '{}': {}", path.display(), err),
26 )
27 })
28}
29
30/// Parses the string, expected to be formatted as credentials file
31pub(crate) fn parse_jwt_and_key_from_creds(contents: &str) -> io::Result<(&str, KeyPair)> {
32 let jwt = parse_decorated_jwt(contents).ok_or_else(|| {
33 io::Error::new(
34 io::ErrorKind::InvalidData,
35 "cannot parse user JWT from the credentials file",
36 )
37 })?;
38
39 let nkey = parse_decorated_nkey(contents).ok_or_else(|| {
40 io::Error::new(
41 io::ErrorKind::InvalidData,
42 "cannot parse nkey from the credentials file",
43 )
44 })?;
45
46 let kp =
47 KeyPair::from_seed(nkey).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
48
49 Ok((jwt, kp))
50}
51
52// This regex parses a credentials file.
53//
54// The credentials file is typically
55// `~/.nkeys/creds/synadia/<account/<account>.creds` and looks like this:
56//
57// ```
58// -----BEGIN NATS USER JWT-----
59// eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5...
60// ------END NATS USER JWT------
61//
62// ************************* IMPORTANT *************************
63// NKEY Seed printed below can be used sign and prove identity.
64// NKEYs are sensitive and should be treated as secrets.
65//
66// -----BEGIN USER NKEY SEED-----
67// SUAIO3FHUX5PNV2LQIIP7TZ3N4L7TX3W53MQGEIVYFIGA635OZCKEYHFLM
68// ------END USER NKEY SEED------
69// ```
70static USER_CONFIG_RE: Lazy<Regex> = Lazy::new(|| {
71 Regex::new(r"\s*(?:(?:[-]{3,}.*[-]{3,}\r?\n)([\w\-.=]+)(?:\r?\n[-]{3,}.*[-]{3,}\r?\n))")
72 .unwrap()
73});
74
75/// Parses a credentials file and returns its user JWT.
76fn parse_decorated_jwt(contents: &str) -> Option<&str> {
77 let capture = USER_CONFIG_RE.captures_iter(contents).next()?;
78 Some(capture.get(1)?.as_str())
79}
80
81/// Parses a credentials file and returns its nkey.
82fn parse_decorated_nkey(contents: &str) -> Option<&str> {
83 let capture = USER_CONFIG_RE.captures_iter(contents).nth(1)?;
84 Some(capture.get(1)?.as_str())
85}