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

Extract hs-ucan from fission-core #571

Merged
merged 47 commits into from
Jan 26, 2022
Merged

Extract hs-ucan from fission-core #571

merged 47 commits into from
Jan 26, 2022

Conversation

matheus23
Copy link
Member

@matheus23 matheus23 commented Jan 18, 2022

This is work on #561

To do this, some dependencies on fission-specific UCAN stuff had to be broken up. The main point here being the definition of Fact and the resource type Scope Resource. (In hindsight I think Scope actually still belongs to hs-ucan, but now I've already done it this way, and we'll have to change these parts of the code when supporting the new UCAN version anyway.)

That means that we can't directly run JWT.check and know how to check delegation validity in UCANs. So I've abstracted that logic out into a ResourceSemantics class:

class ResourceSemantics rsc where
  canDelegate :: rsc -> rsc -> Bool

(Which is structurally equivalent to something like a PartialOrder typeclass, but I like giving it a dedicated name.)

There are still some parts that need work.

  1. I need to still get the tests compiling (and then working?)
  2. I don't 100% like how the fission-core and hs-ucan packages separated. E.g. I don't think Error.AlreadyExists should be a hs-ucan module.
  3. Generally I'll need to look through hs-ucan's .Internal modules again, making sure that we really only have modules in there that make sense
  4. I think I want to introduce a Web.JWT module, which reexports Web.JWT.Types. My current thinking is: Let's introduce that file once we have something to put into it.
  5. I don't like how fission-core's newtype around the hs-ucan JWT works. Either both newtype JWT and newtype Proof or both are type aliases. But if I didn't type-alias Proof, I'd be taking non-newtyped proofs out of JWTs and just re-newtype them. I'm thinking that this might get obsolete when I start working on hs-ucan anyway. I have some recursion-schemes thoughts.
  6. I really don't like the module name Web.JWT.* for the hs-ucan stuff. I'd love some input. Maybe Web.Ucan.*?
  7. Oh yeah and I need to figure out a better way to do the Proof.Resolver class, which now has 3 type parameters instead of one.

And a final TODO item unrelated to hs-ucan or fission-core:

  • Get all other packages & tests compiling again

@matheus23 matheus23 self-assigned this Jan 18, 2022
@matheus23
Copy link
Member Author

matheus23 commented Jan 19, 2022

Don't you like it when your TODO list grows while you're chasing TODO items? :P

  • Re-rename everything to use uppercase UCAN instead of Ucan
  • Abstract over Web.Ucan.Potency
  • Rename ResourceSemantics to DelegationSemantics
  • Split out tests in fission-core (abstract over fission-specific Facts, Resources, Potencys) & move them to hs-ucan

hs-ucan/LICENSE Outdated Show resolved Hide resolved
@@ -27,7 +27,7 @@ data Heroku = Heroku
data Authorization = Authorization
{ sender :: Either Heroku DID
, about :: Entity User
, potency :: Potency
, potency :: Maybe Potency -- Nothing indicates "just used for signature checking"
Copy link
Member

@expede expede Jan 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than dealing with the Maybe for all possible call sites in the future, could we consider either abstracting over Potency, or parsing that case to a different data type? It's not usable if only checking the signature, no? This type is specialized to look at the database with User, so it's not a general use thing. Let's make error cases as unrepresentable as possible, if possible!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make error cases as unrepresentable as possible, if possible!
The new Potency type lacks a variant the old one had before: AuthNOnly. So basically Old.Potency is isomorphic to Maybe New.Potency. So I don't think there should be any changes in terms of what's representable. I basically moved the comment for Nothing over from the definition of the old Potency type.


In any way, as soon as hs-ucan is updated to UCAN 0.8 and I'm incorporating that into the fission stuff, this will change.

Comment on lines -823 to +825
case eitherDecodeStrict resolvedBS of
Left _ -> Left $ InvalidJWT resolvedBS
Right jwt -> Right (JWT.contentOf (decodeUtf8Lenient resolvedBS), jwt)
Right (UCAN.contentOf (decodeUtf8Lenient resolvedBS))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can see an effect of one of the changes.
I've changed the UCAN.Resolver class to only resolve to UCAN.RawContent, instead of also decoding the JWT.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I have some vague memories of also going down this path (several times?) and then putting the JWT back in 🤔 I can't remember what the scenario was — something about needing the decoded case in various code paths? — so not going to say to not do this, but just mentioning it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. I just now realized that RawContent isn't the whole JWT encoded. It's only the part without the signature. That's what I get for not reading its docs!
I'll fix this in another PR. I'm thinking that the easiest way is to return either ByteString from resolve, or some kind of newtype?

Comment on lines -8 to +12
, toBase58Text
, fromRawBytes
, stripOptionalPrefix
, stripOptionalPrefixBS
, stripOptionalPrefixLazyBS
, stripOptionalSuffix
, stripOptionalSuffixBS
, stripOptionalSuffixLazyBS
, stripPadding
, stripQuotes
, stripQuotesBS
, stripQuotesLazyBS
, stripN
, stripNBS
, stripNewline
, toBase58Text
, textShow
, wrapIn
, module Web.UCAN.Internal.UTF8
Copy link
Member Author

@matheus23 matheus23 Jan 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't quite sure what to do with the .Internal stuff that we've been depending on in fission-core.

So what I did was split it up, you can see me removing stuff from the fission-core .Internal.UTF8 module here, and instead reexporting the Web.UCAN.Internal.UTF8 module, where that stuff was moved to.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm good point! A bunch of this stuff is actually now available in other libraries. We could switch to those, or break out a fission-utils or something 🤔

@@ -12,30 +16,30 @@ append-only rights, so

-- | How much power allowed in an authorization
data Potency
= AuthNOnly -- ^ Read signature only -- just a proof. Cannot delegate further.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the AuthNOnly constructor here, in favor of using Maybe Potency instead of Potency everywhere.
The reason is that in hs-ucan we don't want to depend on Potency (because it's also fission-specific), but we need to decode to some potency in case the ptc key is missing completely.

Copy link
Member

@expede expede Jan 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, for this version of UCAN totally.

Thinking out loud: as we bring things to up date, I imagine that we'll have something like...

data Capabilities custom
  = AuthNOnly -- None
  | UserDefined [custom] -- Some
  | AllByParenthood DID -- All (e.g. Linking)

...but obviously we need to actually solidify that in the v0.8 spec before we do that.

Comment on lines +60 to +80
canDelegate rsc rscProof =
case (rsc, rscProof) of
(FissionFileSystem path, FissionFileSystem proofPath) ->
case (isPrivate path, isPrivate proofPath, pathSubset path proofPath) of
(True, True, _) ->
bitwiseContains proofPath path

(_, _, True) ->
True

_ ->
False

(RegisteredDomain _, RegisteredDomain Complete) ->
True

(FissionApp _, FissionApp Complete) ->
True

_ ->
rsc == rscProof
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is code adapted from a previous function Fission.Web.Auth.Token.JWT.Proof.WNFS.compareSubsets

import Web.UCAN.Resolver.Error as Resolver

class Monad m => Resolver m where
resolve :: CID -> m (Either Resolver.Error UCAN.RawContent)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's what I've been talking about (above?): The Resolver class now returns
Either Resolver.Error UCAN.RawContent instead of
Either Resolver.Error (UCAN.RawContent, UCAN.UCAN fct ptc rsc),
which just makes it a little simpler by getting rid of some dependencies on what fct, ptc and rsc are.

This was referenced Jan 24, 2022
@matheus23 matheus23 changed the base branch from main to ucan-upgrade January 25, 2022 13:23
@matheus23
Copy link
Member Author

I've changed the base branch to ucan-upgrade as per discussion with @expede: We'll keep that as another branch running alongside main while we're upgrading hs-ucan, so we can merge partially-typechecking PRs while stuff is in flux.
We keep main clean so we can hotfix stuff.
Eventually ucan-upgrade will get merged into main.

instance DelegationSemantics rsc => DelegationSemantics (Scope rsc) where
Complete `canDelegate` _ = True
(Subset _) `canDelegate` Complete = False
(Subset rscProof) `canDelegate` (Subset rsc) = rscProof `canDelegate` rsc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

Copy link
Member

@expede expede left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matheus23 this looks great 🎉

It's a lot of files, but the changes are extremely straightforward 👍

@matheus23 matheus23 merged commit 04f4df3 into ucan-upgrade Jan 26, 2022
@matheus23 matheus23 deleted the matheus23/hs-ucan branch January 26, 2022 15:29
matheus23 added a commit that referenced this pull request Jan 27, 2022
* Add ipfs in hie.yaml

* Move fission-core tests into fission-core

* Move Fission.Test.Web.Server.Auth to Fission.Test.Web.Auth

* Move some modules around

* Move SemVer and Potency over

* Move key stuff

* Move Internal & Orphanage stuff

* Format files

* Remove remaining dependencies

* Remove hie.yaml

* Move over hs-ucan stuff

* Remove most Fission.Prelude imports from hs-ucan

* Abstract out facts & resource types in JWT

* Format files

* Make hs-ucan and fission-core compile

* Make fission-core compile & run

* Rename a test function

* Move AlreadyExists back to fission-core

* Format files & don't duplicate UTF8 helpers

* Also re-export symmetric in Fission/Key

* Use type alias instead of newtype

* Move things from Web.JWT or Ucan.Internal to Web.Ucan

* Rename JWT stuff into Ucan

* Make Resolver use only a single type param

* Format files

* Revert "Format files"

This reverts commit b6504d9.

* Format files

* Get everything compiling except for fission-web-server

* Make everything COMPILE AGAIN 🙌

* Use the same uppercase UCAN everywhere

* Upgrade cachix/install-nix-action@v16

* Move Potency type to fission-core (& make it Maybe)

* Add a test for Potency

* Make everything compile (& format)

* Rename `ResourceSemantics` to `DelegationSemantics`

* Once and forall fix this broken test

* Initialise test suite in hs-ucan

* Write partial order property tests for canDelegate

* Copy over some tests and write some new

* Fix signature

* Don't use Flow

* Fix imports

* Switch LICENSE to Apache 2

* Use >>= instead of <&>

* Remove unneccesary AllowAmbigousTypes

* We need more $$$

* Even more $$$
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants