Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upIssue287: create random password from a set of allowed characters #372
Conversation
ludwigpacifici
reviewed
Nov 27, 2017
|
|
||
| [![rand-badge]][rand] [![cat-text-processing-badge]][cat-text-processing] | ||
|
|
||
| Randomly generates a string of given length ASCII characters in the range `A-Z, a-z, 0-9`. |
This comment has been minimized.
This comment has been minimized.
ludwigpacifici
Nov 27, 2017
Contributor
Can you give more details, such as gen_ascii_chars is the method which a hardcoded range of character.
Plus, I would show the choose method which is a user defined set of allowed characters. Maybe wait for the green flag of @budziq for this one.
This comment has been minimized.
This comment has been minimized.
budziq
Nov 28, 2017
Collaborator
Agreed on both arguments:
- lets add links to key identifiers in the description.
- I'd suggest to add two snippets here the second one being an iterator based in
chooselike the one used to implementgen_ascii_charsbut taking arbitrary bytestring in the constructor, then used in identical fashion as the first trivial snippet. That would be very cool!
budziq
requested changes
Nov 28, 2017
|
few suggestions |
| @@ -8,6 +8,7 @@ | |||
| | [Generate random numbers within a range][ex-rand-range] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Generate random numbers with given distribution][ex-rand-dist] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Generate random values of a custom type][ex-rand-custom] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Create random passwords from a set of allowed characters][ex-rand-passwd] | [![rand-badge]][rand] | [![cat-text-processing-badge]][cat-text-processing] | | |||
This comment has been minimized.
This comment has been minimized.
budziq
Nov 28, 2017
Collaborator
I'd remove the "text-processing" category. We are not really doing any processing of input text.
| use rand::{thread_rng, Rng}; | ||
| fn main() { | ||
| let s: String = |
This comment has been minimized.
This comment has been minimized.
|
|
||
| [![rand-badge]][rand] [![cat-text-processing-badge]][cat-text-processing] | ||
|
|
||
| Randomly generates a string of given length ASCII characters in the range `A-Z, a-z, 0-9`. |
This comment has been minimized.
This comment has been minimized.
budziq
Nov 28, 2017
Collaborator
Agreed on both arguments:
- lets add links to key identifiers in the description.
- I'd suggest to add two snippets here the second one being an iterator based in
chooselike the one used to implementgen_ascii_charsbut taking arbitrary bytestring in the constructor, then used in identical fashion as the first trivial snippet. That would be very cool!
anna-liao
force-pushed the
anna-liao:issue287
branch
from
c99fdf8
to
69e730e
Dec 3, 2017
This comment has been minimized.
This comment has been minimized.
|
r? @budziq @ludwigpacifici I added an example with |
budziq
requested changes
Dec 6, 2017
|
Thanks @anna-liao ! few suggestions below:
|
| @@ -1615,6 +1664,7 @@ fn main() { | |||
| [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html | |||
| [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html | |||
| [`chain_err`]: https://docs.rs/error-chain/*/error_chain/index.html#chaining-errors | |||
| [`choose`]: https://docs.rs/rand/0.3.18/rand/trait.Rng.html#method.choose | |||
This comment has been minimized.
This comment has been minimized.
| @@ -1639,6 +1689,7 @@ fn main() { | |||
| [`File::try_clone`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.try_clone | |||
| [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html | |||
| [`foreign_links`]: https://docs.rs/error-chain/*/error_chain/#foreign-links | |||
| [`gen_ascii_chars`]: https://docs.rs/rand/0.3.18/rand/trait.Rng.html#method.gen_ascii_chars | |||
This comment has been minimized.
This comment has been minimized.
| let s: String = thread_rng().gen_ascii_chars().take(30).collect(); | ||
| println!("{}", s); | ||
| let alphanum_bytestring = |
This comment has been minimized.
This comment has been minimized.
budziq
Dec 6, 2017
Collaborator
I'd suggest implementing an iterator type like the AsciiGenerator instead that would take an rng in a constructor and for added merrit a "charset" (a hardcoded bytestr for our purposes without anych dynamic generation with ranges and chain) as an argument.
Then it would be used almost identically as the gen_ascii_chars
| let mut rand_bytevec: Vec<u8> = Vec::new(); | ||
| for _ in 0..30 { |
This comment has been minimized.
This comment has been minimized.
budziq
Dec 6, 2017
Collaborator
If the iterator approach would be used, pretty much all of this code would be not needed.
| @@ -8,6 +8,7 @@ | |||
| | [Generate random numbers within a range][ex-rand-range] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Generate random numbers with given distribution][ex-rand-dist] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Generate random values of a custom type][ex-rand-custom] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Create random passwords from a set of allowed characters][ex-rand-passwd] | [![rand-badge]][rand] | | | |||
This comment has been minimized.
This comment has been minimized.
| @@ -26,6 +26,7 @@ community. It needs and welcomes help. For details see | |||
| | [Generate random numbers within a range][ex-rand-range] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Generate random numbers with given distribution][ex-rand-dist] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Generate random values of a custom type][ex-rand-custom] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | |||
| | [Create random passwords from a set of allowed characters][ex-rand-passwd] | [![rand-badge]][rand] | | | |||
This comment has been minimized.
This comment has been minimized.
| String::from_utf8((b'a'..b'z') | ||
| .chain(b'A'..b'Z') | ||
| .chain(b'0'..b'9') | ||
| //.chain([b'!', b'?', b'%']) |
This comment has been minimized.
This comment has been minimized.
budziq
Dec 6, 2017
Collaborator
It does not work because ranges give you u8 while iterating over slice gives you &u8 so the solution (if we wanted to go with this approach and we do not ;)) would be to clone the iterator contents.
.chain([b'!', b'?', b'%'].iter().cloned()) or even better .chain(b"!?%".iter().cloned()).
On the other hand I would suggest to just go with bytestring literal
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789)(*&^%$#@!~";
anna-liao
force-pushed the
anna-liao:issue287
branch
from
69e730e
to
e845d5c
Dec 6, 2017
This comment has been minimized.
This comment has been minimized.
|
@budziq Thanks for the review. I revised the PR based on your suggestions. With the |
budziq
requested changes
Dec 6, 2017
|
@anna-liao few suggestions below :) |
| use rand::{thread_rng, Rng}; | ||
| fn main() { | ||
| let s: String = thread_rng().gen_ascii_chars().take(30).collect(); |
This comment has been minimized.
This comment has been minimized.
| let mut s = String::new(); | ||
| for _ in 0..30 { | ||
| s.push(*thread_rng().choose(CHARSET).unwrap() as char); |
This comment has been minimized.
This comment has been minimized.
budziq
Dec 6, 2017
Collaborator
instead of for loop you can use a relatively simpler functional appproach without a need for manual string append. Also obtaining a thread_rng might be relatively costly so lets reuse one instance througth the generation process.
let mut rng = thread_rng();
let password: String = (0..30)
.map(|_| *rng.choose(CHARSET).unwrap() as char)
.collect();This version might be more readable and concise than separate type approach with CustomGenerator so I'll leave it up to you to chose one.
| } | ||
| } | ||
| fn gen_rand_chars<'a>(&'a mut self) -> CustomGenerator<'a, Self> where Self: Sized { |
This comment has been minimized.
This comment has been minimized.
budziq
Dec 6, 2017
Collaborator
I guess that you are trying to emulate the gen_ascii_chars method here but it is not possible to extend the Rng in such way. All we can do is prepare a standard constructor that will take an rng and a charset.
Some along the lines of
impl<'a, R> CustomGenerator<'a, R> {
fn new(rng: R, charset: &'a [u8]) -> Result<Self> {
if charset.len() > 0 {
Some(CustomGenerator {
rng: rng,
charset: charset,
})
} else {
Err(ErrorKind::InvalidCharset.into())
}
}
}| use rand::{thread_rng, Rng}; | ||
| struct CustomGenerator<'a, R:'a> { | ||
| rng: &'a mut R, |
This comment has been minimized.
This comment has been minimized.
budziq
Dec 6, 2017
Collaborator
I'd probably go with owing the rng to make the lifetimes simpler. But I'll leave it up to you :)
We might go with having a refference to some outsude charset
anna-liao
force-pushed the
anna-liao:issue287
branch
3 times, most recently
from
8f8eef6
to
6013912
Dec 7, 2017
This comment has been minimized.
This comment has been minimized.
|
@budziq Thanks for the help! I have learned more about idiomatic Rust syntax. I decided to stick with the non-generator case for user-specified charset. I couldn't get the generator case working. I think the generator case would be good as an additional example? |
budziq
requested changes
Dec 8, 2017
|
Minor suggestions in a review
No problem it is a bit verbose anyway |
| let mut rng = thread_rng(); | ||
| let password: String = (0..30) | ||
| .map(|_| *rng.choose(CHARSET).unwrap() as char) |
This comment has been minimized.
This comment has been minimized.
budziq
Dec 8, 2017
Collaborator
we generally avoid unwrap in the examples, we should either document why the unwrap will be always ok as long as the CHARSET is nonempty or provide a generalized solution like:
let password: Option<String> = (0..30)
.map(|_| Some(*rng.choose(CHARSET)? as char))
.collect();
println!("{:?}", password);
This comment has been minimized.
This comment has been minimized.
anna-liao
Dec 12, 2017
Author
Contributor
@budziq Thanks for showing me how to implement the generator case! I have updated the PR as suggested to remove the unwrap() and print an Option instead.
anna-liao commentedNov 27, 2017
•
edited
fixes #287 r? @budziq
I categorized this example under
text processing. Do you think that is the appropriate category?