Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop dependency on deriving-aeson; update to Aeson 2 #115

Merged
merged 4 commits into from Jan 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -24,7 +24,7 @@ jobs:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

- name: "Nix build"
run: nix-build -A webauthn -A server
run: nix-build -A webauthn -A server -A webauthn_aeson1

dev:
runs-on: ${{ matrix.os }}
Expand Down
6 changes: 6 additions & 0 deletions changelog.md
@@ -1,3 +1,9 @@
### Next version

* [#115](https://github.com/tweag/webauthn/pull/115) Increase the upper bound
of the supported Aeson versions, allowing the library to be built with Aeson
2.x. Drop the deriving-aeson dependency.

### 0.1.1.0

* [#111](https://github.com/tweag/webauthn/pull/111) Support the
Expand Down
85 changes: 59 additions & 26 deletions default.nix
@@ -1,11 +1,11 @@
{ isShell ? false, system ? builtins.currentSystem }:
let
# Read in the Niv sources
sources = import ./nix/sources.nix {};
sources = import ./nix/sources.nix { };

pkgs = import sources.nixpkgs {
overlays = [];
config = {};
overlays = [ ];
config = { };
inherit system;
};

Expand All @@ -17,30 +17,62 @@ let
# Keep this in sync with the `tested-with` field in `webauthn.cabal`
expectedGhcVersion = "8.10.7";

hpkgs = pkgs.haskellPackages.extend (hself: hsuper: {
ghc =
if hsuper.ghc.version != expectedGhcVersion then
throw
( "We expect the default nixpkgs GHC version to be ${expectedGhcVersion}, "
+ "but it is ${hsuper.ghc.version} instead. Update the `expectedGhcVersion` "
+ "variable in `default.nix` and update the `tested-with` field in "
+ "`webauthn.cabal` at the same time.")
else hsuper.ghc;
hpkgs_aeson1 = pkgs.haskellPackages.extend
(hself: hsuper: {
ghc =
if hsuper.ghc.version != expectedGhcVersion then
throw
("We expect the default nixpkgs GHC version to be ${expectedGhcVersion}, "
+ "but it is ${hsuper.ghc.version} instead. Update the `expectedGhcVersion` "
+ "variable in `default.nix` and update the `tested-with` field in "
+ "`webauthn.cabal` at the same time.")
else hsuper.ghc;

webauthn = pkgs.haskell.lib.disableLibraryProfiling
(hself.callCabal2nix "webauthn" src {});
webauthn = pkgs.haskell.lib.disableLibraryProfiling
(hself.callCabal2nix "webauthn" src { });

server = hself.callCabal2nix "server" (src + "/server") {};
server = hself.callCabal2nix "server" (src + "/server") { };

jose = hself.callHackage "jose" "0.8.5" {};
jose = hself.callHackage "jose" "0.8.5" { };

base64-bytestring = hself.base64-bytestring_1_2_1_0;
base64-bytestring = hself.base64-bytestring_1_2_1_0;

x509-validation = hself.callHackageDirect {
pkg = "x509-validation";
ver = "1.6.12";
sha256 = "1jrsryn6hfdmr1b1alpj5zxvw26dw8y7kqpq555q2njm3kvwmxap";
} {};
x509-validation = hself.callHackageDirect
{
pkg = "x509-validation";
ver = "1.6.12";
sha256 = "1jrsryn6hfdmr1b1alpj5zxvw26dw8y7kqpq555q2njm3kvwmxap";
}
{ };
});

hpkgs = hpkgs_aeson1.extend (hself: hsuper: {

jose = hself.jose_0_9;

aeson = hself.aeson_2_0_3_0;
ErinvanderVeen marked this conversation as resolved.
Show resolved Hide resolved

OneTuple = hself.OneTuple_0_3_1;

hashable = hself.hashable_1_4_0_1;

quickcheck-instances = hself.quickcheck-instances_0_3_27;

text-short = pkgs.haskell.lib.dontCheck hself.text-short_0_1_5;

semialign = hself.semialign_1_2_0_1;

hspec-expectations-json = pkgs.haskell.lib.dontCheck hself.hspec-expectations-json_1_0_0_5;

attoparsec = hself.attoparsec_0_14_3;

time-compat = hself.time-compat_1_9_6_1;

# Needed for aeson 2.0
http2 = pkgs.haskell.lib.appendPatch hsuper.http2 (pkgs.fetchpatch {
url = "https://github.com/kazu-yamamoto/http2/commit/0a1f64cb7cd2042554cd2d4e96da850a8940f08d.patch";
sha256 = "0kbbd7dv49m6slcfw61kzy21v4d2ingnbygg4i3spn91v3dyh87y";
});
});

deploy = pkgs.writeShellScriptBin "deploy" ''
Expand Down Expand Up @@ -75,7 +107,8 @@ let
};

in
if isShell then shell else {
inherit (hpkgs) webauthn server;
inherit pkgs hpkgs;
}
if isShell then shell else {
webauthn_aeson1 = hpkgs_aeson1.webauthn;
inherit (hpkgs) webauthn server;
inherit pkgs hpkgs;
}
6 changes: 3 additions & 3 deletions nix/sources.json
Expand Up @@ -17,10 +17,10 @@
"homepage": "",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0432195a4b8d68faaa7d3d4b355260a3120aeeae",
"sha256": "0izvjizdn0mil4qasdial3hbparzzpx61v0l9zb7bbwss428x1i9",
"rev": "f3d9d4bd898cca7d04af2ae4f6ef01f2219df3d6",
"sha256": "0kngzmn69izr8xcmjiqsyhs80iha00q4nbmj1vs49jrha5ncy8s1",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/0432195a4b8d68faaa7d3d4b355260a3120aeeae.tar.gz",
"url": "https://github.com/NixOS/nixpkgs/archive/f3d9d4bd898cca7d04af2ae4f6ef01f2219df3d6.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}
2 changes: 1 addition & 1 deletion server/server.cabal
Expand Up @@ -31,7 +31,7 @@ executable server

build-depends:
base >= 4.14.3 && < 4.15,
aeson >= 1.5.6 && < 1.6,
aeson >= 1.5.6 && < 3.0,
bytestring >= 0.10.12 && < 0.11,
containers >= 0.6.5 && < 0.7,
binary >= 0.8.8 && < 0.9,
Expand Down
35 changes: 19 additions & 16 deletions src/Crypto/WebAuthn/Internal/Utils.hs
Expand Up @@ -5,10 +5,8 @@
--
-- Internal utilities
module Crypto.WebAuthn.Internal.Utils
( JSONEncoding,
EnumJSONEncoding,
Aeson.CustomJSON (..),
Lowercase,
( jsonEncodingOptions,
enumJSONEncodingOptions,
failure,
certificateSubjectKeyIdentifier,
IdFidoGenCeAAGUID (..),
Expand All @@ -23,32 +21,37 @@ import Data.ASN1.Parse (ParseASN1, getNext, runParseASN1)
import qualified Data.ASN1.Parse as ASN1
import Data.ASN1.Prim (ASN1 (OctetString))
import qualified Data.ASN1.Types as ASN1
import qualified Data.Aeson as Aeson
import Data.Bifunctor (first)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.Char (toLower)
import Data.List (stripPrefix)
import Data.List.NonEmpty (NonEmpty)
import Data.Maybe (fromMaybe)
import qualified Data.UUID as UUID
import Data.Validation (Validation (Failure))
import Data.X509 (Extension)
import qualified Data.X509 as X509
import qualified Deriving.Aeson as Aeson
import GHC.TypeLits (Symbol)

-- | Custom JSONEncoding for use in the library. We add a "lit" prefix to every
-- | Custom Aeson Options for use in the library. We add a "lit" prefix to every
-- field that would otherwise be a Haskell keyword.
type JSONEncoding = Aeson.CustomJSON '[Aeson.OmitNothingFields, Aeson.FieldLabelModifier (Aeson.StripPrefix "lit")]

-- | Type for 'Aeson.StringModifier' that makes all characters lowercase
data Lowercase

-- | Deriving.Aeson instance turning a string into lowercase.
instance Aeson.StringModifier Lowercase where
getStringModifier = map toLower
jsonEncodingOptions :: Aeson.Options
jsonEncodingOptions =
Aeson.defaultOptions
{ Aeson.omitNothingFields = True,
Aeson.fieldLabelModifier = \l -> fromMaybe l $ stripPrefix "lit" l
}

-- | Custom JSON Encoding for enumerations, strips the given prefix and maps
-- all constructors to lowercase.
type EnumJSONEncoding (prefix :: Symbol) = Aeson.CustomJSON '[Aeson.ConstructorTagModifier '[Aeson.StripPrefix prefix, Lowercase]]
enumJSONEncodingOptions :: String -> Aeson.Options
enumJSONEncodingOptions prefix =
Aeson.defaultOptions
{ Aeson.omitNothingFields = True,
Aeson.fieldLabelModifier = \l -> fromMaybe l $ stripPrefix prefix l,
Aeson.constructorTagModifier = \l -> map toLower . fromMaybe l $ stripPrefix prefix l
}

-- | A convenience function for creating a 'Validation' failure of a single
-- 'NonEmpty' value
Expand Down
59 changes: 49 additions & 10 deletions src/Crypto/WebAuthn/Metadata/FidoRegistry.hs
Expand Up @@ -15,9 +15,8 @@ module Crypto.WebAuthn.Metadata.FidoRegistry
)
where

import Crypto.WebAuthn.Internal.Utils (EnumJSONEncoding)
import Crypto.WebAuthn.Internal.Utils (enumJSONEncodingOptions)
import qualified Data.Aeson as Aeson
import Deriving.Aeson (CustomJSON (CustomJSON))
import GHC.Generics (Generic)

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#user-verification-methods)
Expand All @@ -36,7 +35,12 @@ data UserVerificationMethod
| USER_VERIFY_NONE
| USER_VERIFY_ALL
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "USER_VERIFY_" UserVerificationMethod

instance Aeson.FromJSON UserVerificationMethod where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "USER_VERIFY_"

instance Aeson.ToJSON UserVerificationMethod where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "USER_VERIFY_"
ErinvanderVeen marked this conversation as resolved.
Show resolved Hide resolved

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#key-protection-types)
data KeyProtectionType
Expand All @@ -46,15 +50,25 @@ data KeyProtectionType
| KEY_PROTECTION_SECURE_ELEMENT
| KEY_PROTECTION_REMOTE_HANDLE
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "KEY_PROTECTION_" KeyProtectionType

instance Aeson.FromJSON KeyProtectionType where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "KEY_PROTECTION_"

instance Aeson.ToJSON KeyProtectionType where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "KEY_PROTECTION_"

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#matcher-protection-types)
data MatcherProtectionType
= MATCHER_PROTECTION_SOFTWARE
| MATCHER_PROTECTION_TEE
| MATCHER_PROTECTION_ON_CHIP
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "MATCHER_PROTECTION_" MatcherProtectionType

instance Aeson.FromJSON MatcherProtectionType where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "MATCHER_PROTECTION_"

instance Aeson.ToJSON MatcherProtectionType where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "MATCHER_PROTECTION_"

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#authenticator-attachment-hints)
data AuthenticatorAttachmentHint
Expand All @@ -68,7 +82,12 @@ data AuthenticatorAttachmentHint
| ATTACHMENT_HINT_READY
| ATTACHMENT_HINT_WIFI_DIRECT
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "ATTACHMENT_HINT_" AuthenticatorAttachmentHint

instance Aeson.FromJSON AuthenticatorAttachmentHint where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "ATTACHMENT_HINT_"

instance Aeson.ToJSON AuthenticatorAttachmentHint where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "ATTACHMENT_HINT_"

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#transaction-confirmation-display-types)
data TransactionConfirmationDisplayType
Expand All @@ -78,7 +97,12 @@ data TransactionConfirmationDisplayType
| TRANSACTION_CONFIRMATION_DISPLAY_HARDWARE
| TRANSACTION_CONFIRMATION_DISPLAY_REMOTE
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "TRANSACTION_CONFIRMATION_DISPLAY_" TransactionConfirmationDisplayType

instance Aeson.FromJSON TransactionConfirmationDisplayType where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "TRANSACTION_CONFIRMATION_DISPLAY_"

instance Aeson.ToJSON TransactionConfirmationDisplayType where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "TRANSACTION_CONFIRMATION_DISPLAY_"

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#authentication-algorithms)
data AuthenticationAlgorithm
Expand All @@ -101,7 +125,12 @@ data AuthenticationAlgorithm
| ALG_SIGN_SECP512R1_ECDSA_SHA512_RAW
| ALG_SIGN_ED25519_EDDSA_SHA512_RAW
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "ALG_SIGN_" AuthenticationAlgorithm

instance Aeson.FromJSON AuthenticationAlgorithm where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "ALG_SIGN_"

instance Aeson.ToJSON AuthenticationAlgorithm where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "ALG_SIGN_"

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#public-key-representation-formats)
data PublicKeyRepresentationFormat
Expand All @@ -111,7 +140,12 @@ data PublicKeyRepresentationFormat
| ALG_KEY_RSA_2048_DER
| ALG_KEY_COSE
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "ALG_KEY_" PublicKeyRepresentationFormat

instance Aeson.FromJSON PublicKeyRepresentationFormat where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "ALG_KEY_"

instance Aeson.ToJSON PublicKeyRepresentationFormat where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "ALG_KEY_"

-- | [(spec)](https://fidoalliance.org/specs/common-specs/fido-registry-v2.1-ps-20191217.html#authenticator-attestation-types)
data AuthenticatorAttestationType
Expand All @@ -120,4 +154,9 @@ data AuthenticatorAttestationType
| ATTESTATION_ECDAA
| ATTESTATION_ATTCA
deriving (Show, Eq, Generic)
deriving (Aeson.FromJSON, Aeson.ToJSON) via EnumJSONEncoding "ATTESTATION_" AuthenticatorAttestationType

instance Aeson.FromJSON AuthenticatorAttestationType where
parseJSON = Aeson.genericParseJSON $ enumJSONEncodingOptions "ATTESTATION_"

instance Aeson.ToJSON AuthenticatorAttestationType where
toJSON = Aeson.genericToJSON $ enumJSONEncodingOptions "ATTESTATION_"