Giter Club home page Giter Club logo

ironweb's Introduction

IronCore Labs JavaScript SDK

Build Status NPM Version

SDK for using IronCore from your browser-based JavaScript application. Read our documentation for further information about how to integrate this library into your client side application.

Installation

npm install @ironcorelabs/ironweb

Quickstart

Three quick-starts are available on the documentation site. These quick-starts will guide you through getting started with the IronWeb SDK in either a vanilla JS, React , or Angular codebase.

Types

This library contains a TypeScript definitions file which shows the available classes and methods for this SDK.

Local Development

Unit Testing and Linting

This repo uses NPM scripts in order to run all tests and linting. You can run both the unit tests and linting together by running yarn test.

Linting

TSLint and ESLint are used to run linting on all source code. In addition this repo has a Prettier configuration to auto-format source code upon save. Prettier should be configured within your IDE before contributing to this project.

yarn run lint

Unit Testing

This repo uses jest and nightwatch for all unit testing. The unit tests are run using a headless version of Chrome to verify that all tests work in a browser-based environment.

yarn run unit

To run a subset of the tests you can use the -t option of Jest to only run tests whose name matches the provided value

yarn run unit GroupCrypto

Copyright (c) 2022 IronCore Labs, Inc. All rights reserved.

ironweb's People

Contributors

bobwall23 avatar cjyar avatar clintfred avatar coltfred avatar dependabot[bot] avatar ernieturner avatar leeroy-travis avatar skeet70 avatar toniaschlick avatar zmre avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

Forkers

rogervaas

ironweb's Issues

Log SDK version on REST calls

As an IronCore audit log user
I want to know what SDK and version make a request to the IronCore service

  • so that SDKs with specific behaviors/defects can be recognized and isolated
  • so that I can tell if there are out of date clients making requests for encrypted data

AC:

  • Every REST request to the IronCore service should include a header X-IronCore-Sdk-Version. Values of the header should be of the form ironweb <MAJOR>.<MINOR>.<PATCH> and should match the current version of the SDK sending the request.
  • This header should be visible at the ironcore service and should be logged to the requests audit trail

Open questions

  • Are we logging the version of the frame or the shim?
    Open answers
  • The frame

Support policy-based encryption

In addition to explicit access grants, we want to allow a server-side policy to dynamically determine users/groups that a document should be encrypted to.

Encrypt operations should now take explicit grants or policy grants or both types concurrently. Once the policy is evaluated, at least one grant must be specified.

See IronCoreLabs/ironoxide#15 , IronCoreLabs/ironoxide#16

Auto generate types via tsc instead of manually defining them

We've reached a point where manually maintaining the IronWeb TS types is becoming annoying and we should instead look into having tsc generate them for us. This will involve a number of changes including

  • Removing the globals.d.ts file and moving those types into a separate, imported, .d.ts file
  • Removing the ironweb.d.ts file and moving the types it defines somewhere else, probably the same place the globals.d.ts file moves
  • Adding a build step which auto generates the types and adds those to the resulting build output that is published to NPM. Various tweaks will be needed to here to only generate the types we need, i.e. nothing that is included in the frame, only what is exposed via the shim.

Migrate CI to Github Actions

Travis has been incredibly slow to start running CI recently, blocking release processes. Migrate our CI/automated releasing in this repo to Github Actions to match many of our other repos and speed up deployment.

Buffer is transfered to the frame on decrypt.

In order to avoid copying potentially large amounts of data we currently transfer ownership of the underlying buffer when we encrypt/decrypt. This works well when we have a buffer that won't be reused, but does not work well if the buffer will be reused (as it causes all Uint8Arrays on top of that buffer to appear empty).

We should not transfer the buffers across to the frame to avoid callers seeing this kind of issue.

In order to work around this, callers can call .slice(0) on their Uint8Arrays before passing them to cause a copy to be made.

Support group private key rotation

As a group admin
I want to be able to rotate my private key (without changing my public key)
so that I can be sure that anyone who had access to the old private key can't administer the group after rotation.

AC:
sdk.group.rotatePrivateKey(groupID: string)
Must verify that the user trying to rotate the key is an admin of the group.
Similar to user rotate, generate a new plaintext and perform subtraction.
Re-encrypt new plaintext to all existing admins.
Push updated information to new group API endpoint (PUT /groups/{id}/keys/{keyId})

See IronCoreLabs/ironoxide#45

Cache user and group public keys

As an ironweb-enabled app
I want to only have to call the ironcore-ws to get public keys once per session
so that I can realize a performance increase for encrypt operations

As of today there is no way for a user or group public key to change, so it should always be safe to cache public keys in memory. I don't think we should go so far as to cache them in local storage at this point.

Before this ticket is closed be sure to open one in other SDKs.

`changePasscode` doesn't change localstorage private key

We ran into this in one of our implementations.

If changePasscode succeeds, ironweb doesn't change the ApiState.encryptedPrivateUserKey to the new value. This means that any subsequent calls to changePasscode will fail until the device is deauthorized and re-initialized.

Add timeout to frame loading to reject Promise if frame can't be loaded

We recently had an outage in stage which is the environment we point to for local CMK development. The behavior of this outage meant that the IronWeb frame couldn't be loaded, but we don't have any failure checks to detect that (nor apparently is there a way to add an onerror handler to iframes). This meant that calls to IronWeb.initialize just never resolved and waited forever.

We should add a timeout from the point that we try to append the iFrame so that we only wait a few seconds for the frame to load before we bail out and reject the Promise with an error.

Add currentKeyId to user/group responses

As an SDK method needing the current key id
I want to be able to get the current key id for the current user or for any group the current user is an admin of
so that I can use that key id as part of subsequent requests I'm going to make

AC:
TODO

Related to IronCoreLabs/ironoxide#46

Create Group with initial admins

As an application developer
I want to be able to specify the admins for a group at group creation time
so that I don't have to make additional calls to set up the administrators

AC:

  • the calling user should not be be forced to be an admin or the "owner" of the group
  • the SDK should enforce that at least one admin is specified

related to: IronCoreLabs/ironoxide#66

Create group with needsRotation set

As an application developer
I want to be able to create a cryptographic group before the admins and members have keys
so groups can be created independently of the admins and members

AC:

  • group creation should allow seeing a needsRotation flag.
  • needsRotation is returned as part of the value returned to the caller
  • if needsRotation is set, the calling user should transfer group ownership to another admin and remove themselves as an admin prior to returning from group_create

Also see: IronCoreLabs/ironoxide#64

Create benchmark page

We would like to make it easy for those integrating ironweb to run benchmarks for themselves so they can understand how ironweb is impacting their application in their environment.

As a first step, we should provide a self-hosted benchmark page in the ironweb repository. It should cover most SDK functions, and would ideally run each benchmark a number of times and compute averages and median times.

Add option on document encrypt to not encrypt to current user

Add a new boolean option to IronWeb.document.encrypt, (grantToAuthor default true) to the options that allows callers to not encrypt to the user performing the operation, but only to those users/groups in the provided grant list. Validation must then be performed to verify that at least one user/group is being encrypted to, that is, this flag cannot be turned off if the list of grants is empty.

Not sure, but maybe this should also be added to IronWeb.document.encryptToStore?

See IronCoreLabs/ironoxide#2

Bring test UI up to snuff with latest features

This is a ticket that we should keep updating with things that haven't made it into the test UI.

  • Sharing with a group you are not in
    Add an arbitrary text box on document share to let users manually enter group IDs
  • Creating document without encrypting to current user
    Add a checkbox on document create that lets the user opt out of sharing with themselves on create.

Support decrypt with detached EDEKs

IronWeb should have a new namespace, documentEdek. Inside we should have a function decrypt which takes the encrypted data as well as the edeks. Similar to IronCoreLabs/ironoxide#22 we should send the edeks to the transform service and resume decryption normally.

Can polyfill references be removed?

When working on #97 I came across several references to polyfill as a fallback for cryptographic operations. I don't think these are probably needed anymore.

eg:

    return NativeAes.decryptDeviceAndSigningKeys(devicePrivateKey, signingPrivateKey, symmetricKey, iv).handleWith(() =>
        PolyfillAes.decryptDeviceAndSigningKeys(devicePrivateKey, signingPrivateKey, symmetricKey, iv)
    )

Maybe everything in the PolyFilAes file can be removed? Maybe sjcl can be removed?

Support creation of device keys without storing them locally in the browser

Similar to the server side SDKs, we should have a pre-initialize (i.e. sibling of initialize) that lets a caller generate a new set of device keys given a valid JWT for a user and that users password. This should just return all the same information that is returned in the other SDKs (encryption/signing key pairs, internal segment ID, etc). None of this data should replace any storage of the device keys that might already exist in local storage.

IronWeb.generateDeviceKeys(jwt: string, password: string, {deviceName: string}?): Promise<{
  accountID: string;
  segmentID: number;
  deviceKeys: {publicKey, privateKey},
  signingKeys: {publicKey, privateKey}
}>

Expose substring search functionality

These functions should exist on a namespace on the SDK object.

The search indices will be identified by handles - creating the index generates and encrypts a salt and returns that along with a handle. The initialization function takes an encrypted salt and returns the handle. Inside the frame, there should be a map from handle to decrypted salt. The tokenize calls should also take the handle.

Prepend PBKDF2 iteration count to front of user encrypted private key

Our PBKDF2 iteration could is currently fixed at 250K. Assuming that, as time goes on, we'll want to bump that up, we'll need to store the count with the data in order to have it be variable. We should use the first 4 bytes of the concated bytes (before the salt/IV) to store the count so that we have the ability for it to be variable in the future.

Create user with needsRotation set

As an application developer
I want to be able to create a user's cryptographic identity ahead of them logging in
so that I can add them to groups and/or share data with them.

AC:

  • - user create method takes an options object that allows a user to created with a flag set marking them as needing rotation
  • - needsRotation is returned as part of the value returned to the caller

Also see: IronCoreLabs/ironoxide#38

Update material-ui in integration app

This only really matters for maintenance and security alert purposes, it doesn't affect the code shipped in the library. An attempt to bring MUI up from 0.x to 4.x was started on upgrade-material-ui. All the mechanical things have been done there, but now there are issues that require logic changes to fix.

AC:

  • fix the UI in upgrade-material-ui up so it functions and integration tests pass
  • (optional) migrate from MUI v4 to MUI v5 from that point

Support user private key rotation

As a user
I want to be able to rotate my private key (without changing my public key)
so that I can be sure that anyone who had access to my private key previously, can't decrypt data

AC:

  • add needsRotation property to SDKInitializationResult
  • add rotateCurrUsersPrivateKey(password: string): Promise<UserRotationResult> to the User interface
  • calling rotateCurrUsersPrivateKey should result in the user's private key being changed, and old version of the private key should be useless. Call the PUT users/{userId}/keys/{userKeyId} in the ironcore service.
  • after the private key is rotated, existing device transform keys should continue to work
  • after private key rotation, the needsRotation flag should be unset on subsequent initialilze calls
  • user's currentKeyId added to User Verify and User Create responses. (currentKeyId should not be part of the public API)

Tweak grantToAuthor flag to avoid major version bump

PR #30 was implemented in such a way that it made a breaking change to the shim/frame communication which caused us to bump things a major version. However, the addition was very minor and shouldn't have caused consumers to have to look into why a new major version was released. We should modify the code so that it will work for earlier versions so that this can just become a 3.x version instead.

Send requests using IronCore API auth v2

IronCore auth v2 API auth gives stronger guarantees about tamper evidence of recorded audit information as well as eliminates the possibility of replay-style attacks.

TODO include v2 API auth details

Also see IronCoreLabs/ironoxide#50

NOTE: As part of this, also escape user IDs in the user key list URL that we build up, like we're doing for group operations.

Need to update lodash version

GitHub has reported a high severity security vulnerability in lodash, which is resolved in version 4.17.13.

It appears that the dependency on lodash is not just in build-code, and it looks like there are numerous libraries that have underlying lodash dependencies.

Provide additional useful information in response to createNewDeviceKeys

Currently, the return value from ironweb.createNewDeviceKeys does not make the device ID, name, or created date available, although these fields might be useful for a caller to store. Ensure that this call provides all available information in the response strucutre.

Will need to wait until the API returns the name and created date fields in order to provide them as part of this struct.

Remove support for IE

IE is the only browser that doesn't support WASM so we fall back to using RecryptJS there. However, the performance of that library in IE is basically unusable. Since IE11 is getting pretty old at this point we should clean up a bunch of our code to require WASM supported browsers only.

Support creating a document without granting access to the author

Add a new boolean flag (default true) on document.create which controls whether the author of the document will have the document be encrypted to them. The document.create call must share with at least one user/group, so if this option is false, the grantList must have at least one entry.

Also need to consume changes to how the document list, document get response structures can change if the author is requesting a document that they cannot decrypt.

As part of this ticket we should also update the UI so we can exercise this change in addition to adding UI to consume the change that lets users share documents with groups they are not a part of.

  • Sharing with a group you are not in
    • Add an arbitrary text box on document share to let users manually enter group IDs
  • Creating document without encrypting to current user
    • Add a checkbox on document create that lets the user opt out of sharing with themselves on create.

Allow raw bytes as input on decrypt

Currently the IronWeb decrypt method expects a base64 encrypted string on input. When we started messing around with protobuf, we now have raw bytes. So in order to decrypt we have to convert back to base64, which IronWeb then just immediately converts to bytes. Allowing input of either a string or bytes would be better.

Consume new device APIs

  • We probably won't expose a device name on create for IronWeb since that concept is pretty hidden from other users.
  • Add a device list() method
  • Make a call to device remove when the user calls a User.deauthorizeDevice() method.

Rename Policy

Change the name of the Policy interface to PolicyQuery, update doc comments appropriately.

Add method to let users delete device given a JWT and their escrow password

Once the endpoint in iconcore-id exists, add a new method to the SDK to let a user delete a device given a JWT callback and a password. This should request/decrypt the users master private key and then generate a known signed Schnorr signature and make a request to the API to delete a device.

API method signature should look something like

deviceDelete(jwtCallback: () => Promise<string>, password: string, deviceId: number)

We'll have to come up with a better name to avoid confusion about which deviceDelete method the user should call. This method should probably just live directly off the IronWeb export and we leave the other one on the IronWeb.user. export.

Migrate off of karma and jasmine to Jest

All of our unit tests use Karma and Jasmine for unit testing. These worked out great initially, but now a bunch of the tooling that was necessary to use to get things working are getting out of date, deprecated, and have security issues that won't be fixed. While this is all in test dependencies, it's still really annoying to constantly get these errors.

Similar to our other projects, we should instead change to Jest for everything. For most tests this should be pretty simple since Jest still uses Jasmine under the hood. However, Karma was testing against a "real" browser via chromedriver, and Jest uses js-dom to mock a browser environment. One big downside to this is the fact that js-dom doesn't support window.crypto so we'll need to dig in to see how much work it'll take to mock that out.

Return ID of newly generated device on device create

As part of the payload that we return from our createNewDeviceKeys SDK call we should also return the ID of the device keys that we just created. That way users can store off this ID if necessary and use it in subsequent device delete calls.

Support creation of a new user without automatically generating them device keys

In order to supporting creating "service account" style users, we should add a pre-initialization method to IronWeb (i.e. sibling of initialize) that allows for creation of a user that only generates their master key pair but doesn't create a device key pair/set the current user in SDK state. This should work the same as it does in the Node/Rust server side SDKs

sdk.createUser(jwt: string, password: string): Promise<UserRecord>;

Fix response types to handle missing document encrypted symmetric key

A change was made that allows document owners who are not allowed to decrypt a document (created a document and set grantToAuthor to false) to still be able to call a GET on the document. This can cause a number of JS errors because we currently assume if you can call document GET, you can also decrypt the document. Update the response types and handle the errors that occur in this situation.

Create group with initial members

As as application developer
I want to be able to specify the initial group members on create
so that I don't have to make additional calls to set up the membership

AC:

  • creation method should contain both addAsMember to mark the calling user as a member and members: [UserId] to allow other members to be added
  • return structure for group create should reflect the membership.

I'm uncertain if the web service supports partial failure for adding members on create. If it does, the users that failed to be added to the membership on create should also be included in the result.

Also see IronCoreLabs/ironoxide#65

Automate integration tests

Our current integration test suite is large and comprehensive but is only runnable manually. OSS folks who open PRs can't run them and it's a big process for us to run them manually. Make it possible to trigger integration tests.

For integration tests to run:

  • ironcore-id needs to be running locally with its postgres DB
  • project, assertion key, and segment info that is valid on that ironcore-id instance needs to be in integration/projects/project.json (can probably be canned DB scripts)
  • https certs for dev1.scrambledbits.org need to be up to date (automating this is the hardest part)
  • yarn start needs to run the integration app
  • yarn nightwatch can then run the suite, though that requires chrome to be installed so chromedriver works

A possible workaround to the https certs issue would be to make the integration app not require https, but the scope of that is unknown at the time of writing this ticket.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.