More explicit data type Lang
for language.
This commit is contained in:
parent
889eedbb79
commit
dcf73bd86d
7 changed files with 70 additions and 24 deletions
|
@ -334,7 +334,7 @@ pub fn test_set_user_data(
|
||||||
card_client.set_name(b"Bar<<Foo")?;
|
card_client.set_name(b"Bar<<Foo")?;
|
||||||
|
|
||||||
// lang
|
// lang
|
||||||
card_client.set_lang(b"deen")?;
|
card_client.set_lang(&[['d', 'e'].into(), ['e', 'n'].into()])?;
|
||||||
|
|
||||||
// sex
|
// sex
|
||||||
card_client.set_sex(Sex::Female)?;
|
card_client.set_sex(Sex::Female)?;
|
||||||
|
@ -348,7 +348,7 @@ pub fn test_set_user_data(
|
||||||
assert_eq!(ch.name().as_deref(), Some("Bar<<Foo".as_bytes()));
|
assert_eq!(ch.name().as_deref(), Some("Bar<<Foo".as_bytes()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ch.lang().expect("Language setting is None"),
|
ch.lang().expect("Language setting is None"),
|
||||||
&[[b'd', b'e'], [b'e', b'n']]
|
&[['d', 'e'].into(), ['e', 'n'].into()]
|
||||||
);
|
);
|
||||||
assert_eq!(ch.sex(), Some(Sex::Female));
|
assert_eq!(ch.sex(), Some(Sex::Female));
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use openpgp_card::algorithm::{Algo, AlgoInfo, AlgoSimple};
|
||||||
use openpgp_card::card_do::{
|
use openpgp_card::card_do::{
|
||||||
ApplicationIdentifier, ApplicationRelatedData, CardholderRelatedData,
|
ApplicationIdentifier, ApplicationRelatedData, CardholderRelatedData,
|
||||||
ExtendedCapabilities, ExtendedLengthInfo, Fingerprint, HistoricalBytes,
|
ExtendedCapabilities, ExtendedLengthInfo, Fingerprint, HistoricalBytes,
|
||||||
KeyGenerationTime, PWStatusBytes, SecuritySupportTemplate, Sex,
|
KeyGenerationTime, Lang, PWStatusBytes, SecuritySupportTemplate, Sex,
|
||||||
};
|
};
|
||||||
use openpgp_card::{CardClient, Error, KeySet, KeyType, Response};
|
use openpgp_card::{CardClient, Error, KeySet, KeyType, Response};
|
||||||
|
|
||||||
|
@ -411,12 +411,12 @@ impl Admin<'_, '_> {
|
||||||
self.oc.card_client.set_name(name.as_bytes())
|
self.oc.card_client.set_name(name.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_lang(&mut self, lang: &str) -> Result<Response, Error> {
|
pub fn set_lang(&mut self, lang: &[Lang]) -> Result<Response, Error> {
|
||||||
if lang.len() > 8 {
|
if lang.len() > 8 {
|
||||||
return Err(anyhow!("lang too long").into());
|
return Err(anyhow!("lang too long").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.oc.card_client.set_lang(lang.as_bytes())
|
self.oc.card_client.set_lang(lang)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, Error> {
|
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, Error> {
|
||||||
|
|
|
@ -111,7 +111,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let res = admin.set_sex(Sex::NotApplicable)?;
|
let res = admin.set_sex(Sex::NotApplicable)?;
|
||||||
println!("set sex {:x?}", res);
|
println!("set sex {:x?}", res);
|
||||||
|
|
||||||
let res = admin.set_lang("en")?;
|
let res = admin.set_lang(&[['e', 'n'].into()])?;
|
||||||
println!("set lang {:x?}", res);
|
println!("set lang {:x?}", res);
|
||||||
|
|
||||||
let res = admin.set_url("https://keys.openpgp.org")?;
|
let res = admin.set_url("https://keys.openpgp.org")?;
|
||||||
|
|
|
@ -285,7 +285,7 @@ pub struct ExtendedLengthInfo {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct CardholderRelatedData {
|
pub struct CardholderRelatedData {
|
||||||
name: Option<Vec<u8>>,
|
name: Option<Vec<u8>>,
|
||||||
lang: Option<Vec<[u8; 2]>>,
|
lang: Option<Vec<Lang>>,
|
||||||
sex: Option<Sex>,
|
sex: Option<Sex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,6 +298,45 @@ pub enum Sex {
|
||||||
NotApplicable,
|
NotApplicable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
pub enum Lang {
|
||||||
|
Value([u8; 2]),
|
||||||
|
Invalid(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(char, char)> for Lang {
|
||||||
|
fn from(c: (char, char)) -> Self {
|
||||||
|
Lang::Value([c.0 as u8, c.1 as u8])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[char; 2]> for Lang {
|
||||||
|
fn from(c: [char; 2]) -> Self {
|
||||||
|
Lang::Value([c[0] as u8, c[1] as u8])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Lang> for Vec<u8> {
|
||||||
|
fn from(lang: Lang) -> Self {
|
||||||
|
match lang {
|
||||||
|
Lang::Value(v) => vec![v[0], v[1]],
|
||||||
|
Lang::Invalid(v) => vec![v],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&[u8; 1]> for Lang {
|
||||||
|
fn from(data: &[u8; 1]) -> Self {
|
||||||
|
Lang::Invalid(data[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&[u8; 2]> for Lang {
|
||||||
|
fn from(data: &[u8; 2]) -> Self {
|
||||||
|
Lang::Value([data[0], data[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&Sex> for u8 {
|
impl From<&Sex> for u8 {
|
||||||
fn from(sex: &Sex) -> u8 {
|
fn from(sex: &Sex) -> u8 {
|
||||||
match sex {
|
match sex {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::convert::TryFrom;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::card_do::{CardholderRelatedData, Sex};
|
use crate::card_do::{CardholderRelatedData, Lang, Sex};
|
||||||
use crate::tlv::{value::Value, Tlv};
|
use crate::tlv::{value::Value, Tlv};
|
||||||
|
|
||||||
impl CardholderRelatedData {
|
impl CardholderRelatedData {
|
||||||
|
@ -15,7 +15,7 @@ impl CardholderRelatedData {
|
||||||
self.name.as_deref()
|
self.name.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lang(&self) -> Option<&[[u8; 2]]> {
|
pub fn lang(&self) -> Option<&[Lang]> {
|
||||||
self.lang.as_deref()
|
self.lang.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,17 @@ impl TryFrom<&[u8]> for CardholderRelatedData {
|
||||||
let name: Option<Vec<u8>> =
|
let name: Option<Vec<u8>> =
|
||||||
tlv.find(&[0x5b].into()).map(|v| v.serialize().to_vec());
|
tlv.find(&[0x5b].into()).map(|v| v.serialize().to_vec());
|
||||||
|
|
||||||
let lang: Option<Vec<[u8; 2]>> = tlv
|
let lang: Option<Vec<Lang>> =
|
||||||
.find(&[0x5f, 0x2d].into())
|
tlv.find(&[0x5f, 0x2d].into()).map(|v| {
|
||||||
.map(|v| v.serialize().chunks(2).map(|c| [c[0], c[1]]).collect());
|
v.serialize()
|
||||||
|
.chunks(2)
|
||||||
|
.map(|c| match c.len() {
|
||||||
|
2 => Lang::from(&[c[0], c[1]]),
|
||||||
|
1 => Lang::from(&[c[0]]),
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
|
||||||
let sex = tlv
|
let sex = tlv
|
||||||
.find(&[0x5f, 0x35].into())
|
.find(&[0x5f, 0x35].into())
|
||||||
|
@ -66,7 +74,7 @@ mod test {
|
||||||
ch,
|
ch,
|
||||||
CardholderRelatedData {
|
CardholderRelatedData {
|
||||||
name: Some("Bar<<Foo".as_bytes().to_vec()),
|
name: Some("Bar<<Foo".as_bytes().to_vec()),
|
||||||
lang: Some(vec![[b'd', b'e'], [b'e', b'n']]),
|
lang: Some(vec![['d', 'e'].into(), ['e', 'n'].into()]),
|
||||||
sex: Some(Sex::Female)
|
sex: Some(Sex::Female)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -48,7 +48,7 @@ use crate::apdu::commands;
|
||||||
use crate::apdu::response::RawResponse;
|
use crate::apdu::response::RawResponse;
|
||||||
use crate::card_do::{
|
use crate::card_do::{
|
||||||
ApplicationRelatedData, CardholderRelatedData, Fingerprint,
|
ApplicationRelatedData, CardholderRelatedData, Fingerprint,
|
||||||
KeyGenerationTime, PWStatusBytes, SecuritySupportTemplate, Sex,
|
KeyGenerationTime, Lang, PWStatusBytes, SecuritySupportTemplate, Sex,
|
||||||
};
|
};
|
||||||
use crate::crypto_data::{
|
use crate::crypto_data::{
|
||||||
CardUploadableKey, Cryptogram, Hash, PublicKeyMaterial,
|
CardUploadableKey, Cryptogram, Hash, PublicKeyMaterial,
|
||||||
|
@ -755,8 +755,14 @@ impl<'a> dyn CardClient + 'a {
|
||||||
apdu::send_command(self, put_name, false)?.try_into()
|
apdu::send_command(self, put_name, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_lang(&mut self, lang: &[u8]) -> Result<Response, Error> {
|
pub fn set_lang(&mut self, lang: &[Lang]) -> Result<Response, Error> {
|
||||||
let put_lang = commands::put_lang(lang.to_vec());
|
let bytes: Vec<u8> = lang
|
||||||
|
.iter()
|
||||||
|
.map(|&l| Into::<Vec<u8>>::into(l))
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let put_lang = commands::put_lang(bytes);
|
||||||
apdu::send_command(self, put_lang, false)?.try_into()
|
apdu::send_command(self, put_lang, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,14 +215,7 @@ fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(lang) = crd.lang() {
|
if let Some(lang) = crd.lang() {
|
||||||
let lang = lang
|
println!("Language preferences '{:?}'", lang);
|
||||||
.iter()
|
|
||||||
.map(|lang| {
|
|
||||||
lang.iter().map(|&u| char::from(u)).collect::<String>()
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
println!("Language preferences '{}'", lang);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// information about subkeys
|
// information about subkeys
|
||||||
|
|
Loading…
Reference in a new issue