Git Product home page Git Product logo

decentralized-web-node's People

Contributors

andorsk avatar bezreyhan avatar bumblefudge avatar chriskellylp avatar csuwildcat avatar dependabot[bot] avatar dlamers avatar dlongley avatar dmitrizagidulin avatar doodlemania2 avatar expede avatar gobengo avatar hackmd-deploy avatar ianopolous avatar lirancohen avatar logangirvin avatar margojohnson24 avatar mhailstone avatar mistermoe avatar moisesja avatar msporny avatar nembal avatar oed avatar or13 avatar rhiaro avatar shobitb avatar tallted avatar thedoctor avatar thehenrytsai avatar therecanbeonlyone1969 avatar

Stargazers

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

Watchers

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

decentralized-web-node's Issues

Consider removal of Profile interface

i'm not suggesting that the concept of Profile should be removed. Rather, basic profile information that describes the target DID entity could be exposed through the functionality provided by the Collections. Since the Collections interface provides a mechanism to store and retrieve data relative to shared schemas, it effectively provides a means to store and expose profile data in accordance to a given schema. The same outcome would be achieved with 1 less interface.

The main difference that comes to mind is that Profile interface messages do not require an objectId whereas Collections messages do. To me, this implies that there can only be one profile vs. many instances of the same collection (e.g. more than 1 SocialMediaPosting). This means that, if profile data was stored and retrieved by means of the Collections interface, there could be more than 1 profile.

I'm curious as to what others think about this. Thanks in advance for taking the time to consider!

Last Write Wins commit strategy name is misleading

Is it when the write is done or when the write request is received that counts? The fact that Cassandra used Last Write Wins for the latter confuses the issue. Perhaps "Latest Timestamp" is a better term.

Requiring fine-grained capabilities

The current specification allows the capability for a collection to be used when accessing an individual member of that collection, which is a violation of the Principle of Least Privilege. Of course, the holder of a capability for a collection can always create a new capability for the individual item, but that requires extra work that many people won't do. The result will be that a successful attack will be able to do substantially more harm than had the system required fine-grained capabilities.

It should be possible for the software invoked when submitting a request to construct the fine-grained capability from the one provided by the invoker.

Decide on the encryption strategy for items/files

Requirements to consider:

  • Encryption should allow for external entities to access and decrypt the items they are granted permission for.
  • Encryption should not require undue duplication and expensive client processes to effect (e.g. re-encryption/re-keying)
  • Permissions can change dynamically, adding or removing external entities from access to future modifications of items. We need to decide how we will deal with this, which has impacts across the way encryption and items are structured/linked/bucketed at lower levels in the stack.

Clocks are not trustworthy

Timestamps are used in the last write wins commit strategy, but timestamps are unreliable. Clocks on computers exhibit strange behavior, sometimes jumping forward or even backward. A malicious party can set the timestamp to an arbitrary value. Therefore, a timestamp should only be accepted if it comes from a trusted party or if it was signed by one.

Specify encoder for messageId

In point 3 of Chapter 9.2, it says the messageId must be V1 CID of the message, however it does not specify the encoder, can it be explicitly specified to use DAG-CBOR encoding?

Change DAG-DBOR to DAG-PB for cid implementation

Capture what we have discussed -
The cid for the data will be using DAG-PB with chunking (same as ipfs add). For any object, it will need to be converted to file/byte array first. i.e. JSON object needs to be stringified first. The data field will be populated with base64 encoded byte array of the actual data.
The cid for the request will also be DAG-PB

Decide on and specify a file structure and association model

We need to make a decision about what the underpinning file structure and file association model will be, and get it specified to the point we can be confident an implementer can act on it, and hopefully leverage code from the community to fill the gap.

@expede, @bmann, @justinwb, @carsonfarmer, @wyc I think this would make a ton of sense for the first implementers call, and am hoping we can get this spec'd such that we can use an existing module from the community.

Expected runtime environments

What environments are hubs expected to run in?

The first image in the spec implies that hubs can run "locally" and in "the cloud". Local is presumably mobile devices and browsers. The spec does not address the fact that local hubs will likely have restrictions that prevent them from running as the spec states.

For example, if a local hub is running within a mobile app, is the expectation that the mobile app be running a server that can accept requests from anyone in the world? I realize that hubs are transport agnostic, but it seems to be the case that hubs necessitate listening over some transport.

I think it might be worth clarifying the distinction

Suggestion: Encode request objects as IPLD CAR files.

Was revisiting this spec and I noticed that IPLD (IPFS) is being used in a kind half baked way. Some of the data included in the "request object" is assumed to also be encoded as an IPLD DAG-CBOR object. I believe we can actually encode the entire request object as a set of IPLD objects (e.g. the authorization object is already valid DagJOSE). These IPLD objects can then be put together in a single IPLD CAR file which can be easily transmitted over the wire as bytes encoded in any preferred manner.

This is mostly a suggestion on how IPLD could be used more natively. In the way the spec is written currently I'm not sure exactly what value using IPLD adds.

Sidenote, DagJOSE was merged and released in go-ipfs 🎉

Follow up with IPLD team

It looked like the IPLD email thread hasn't come to a conclusion.

I'm reaching out to the IPLD team to see about meeting live over Zoom, currently aiming for week of July 26th.

We'll use this thread / link a HackMD with some agenda notes and open questions.

Are responses sync, async, or both?

Problem

The spec doesn't indicate whether responses are supposed to be sync, async, or circumstantially either.

I can see use-cases for both sync and async responses though supporting both will be impossible at times depending on the chosen transport layer (e.g. websockets)

Hubs have no way of knowing whether a message requires `authorization`, `attestation`, or data encryption

Problem

The spec does not indicate how an Identity Hub Instance decides whether a message requires authorization, attestation, or for data to be encrypted.

Context

Let's assume the following request is sent to an Identity Hub:

{
    "requestId": "862b44c7-cd7b-4974-8782-b32f470064ef",
    "target": "did:ex:alice",
    "messages": [{
        "descriptor": {
            "objectId": "0f913c1e-cde5-4bbf-956a-80aa481687ad"
            "method": "CollectionsWrite",
            "schema": "https://schema.org/MusicPlaylist",
            "dataFormat": "application/json"
        },
        "data": {...}
    }]
}

The message in the request above does not contain attestation or authorization, nor is data encrypted, yet it is a valid message. Further, even if authorization was provided, Alice's hub instance currently has no clue whether it should expect authorization or not. She should be able to configure what requires any combination of attestation, authorization, and data encryption based on an individual message's descriptor.

if the combinatorial suggestion seems like overkill, i'd like to know why and propose that there should be a way to configure what requires authorization at the very least.

Proposal

This proposal only focuses on supporting configuration of authorization. If there's consensus around supporting configuration of any combination of authorization, attestation, and encryption, we can extend the proposal.

We can borrow the concept of DMZ from routers and loosely apply it here.

Pseudocode

  async processMessage(message) {
    // message validation and other things

    const { descriptor } = message;

    // build DMZ policy out of message's descriptor
    const policy = {};
    for (let field of ['dataFormat', 'method', 'schema']) {
      if (field in descriptor) {
        policy[field] = descriptor[field];
      }
    }

    // check to see if policy is within DMZ
    const isWithinDMZ = !! await this.DMZStore.get(policy);

    // authorization is required if message op is not within DMZ
  }

Logic

  • Build policy out of fields within message.descriptor
  • Check to see if policy exists in hub's DMZ store
  • if it does, no auth is required.
  • Otherwise, expect auth

DMZ Policy Data Model

Field Data Type Required (Y/N)
dataFormat String N
method String N
schema String N

Follow up questions

  • Should DMZ be it's own interface or live underneath the Permissions interface?
    • If as it's own interface, what would that interface look like?
      • would there need to be some hardcoded logic to prevent DMZ checks for DMZ-related messages?
    • if underneath Permissions how would that work? Additional Methods?
  • Are there any DMZ policies that should be included by default?

No Actions specify more than one object, but "capabilities" in authorization field is plural.

A capability designates the object and the permission being authorized on that object. The method in the descriptor field specifies a single operation, and all allowed Actions take a single argument. Hence, there should be only one capability in the authorization field.

The kid field allows for only a single key, but it should be possible to issue each capability to a different key. As long as only one capability can be specified, a single key suffices.

Also, since the capability necessarily designates the object, it can be used in place of the objectId in the descriptor. Each capability should authorize a single permission, so the capability can also be used instead of the method field in the descriptor field.

Missing details how to address different hubs

Reading the spec I see this addressing format did:example:123 + ?service=IdentityHub + &relativeRef=/?message= + { MESSAGE_BODY }

It's unclear how to address different hubs this way?

as a developer, I can follow docs to run the reference implmentation, so I can test it out and then contribute improvements or passing test-suites

#user-story

Acceptance Criteria:

Even better:

  • This should work:
    git clone [email protected]:decentralized-identity/decentralized-web-node.git && cd decentralized-web-node
    npm i
    # -w value corresponds to https://github.com/decentralized-identity/decentralized-web-node/blob/main/packages/implementations/javascript/package.json#L2
    npm -w identity-hub start
    

Inspiration:

Permissions Interface considerations

Permissions Interface Considerations

The following are a handful of considerations that may be useful to give thought to when fleshing out the Permissions interface.

Note: These considerations were formulated based on the spec in it's current state

  • PermissionsRequest cannot require any authorization. It would be seemingly impossible to request any permission without first acquiring the capability to do so out-of-band
    • This means that PermissionsRequest will likely be the first candidate for DoS attacks
  • PermissionsRequest will require human intervention.
    • How will that Permissions Request get to Alice?
      • Assuming it does, how will Alice know what she's granting permissions for?
        • seems like the capability data model will, at the very least, require a description and extendedDescription.
          • The Capability model isn't yet defined but description should be auto generated based on what's being requested. This is a weak guard against permissions requesters outright lying about what they're requesting access to and getting away with it. extendedDescription can be populated by the requester
    • how does Alice send the capability back to the requester?
      • is it an assumed requirement that the requester is also operating a hub that can be identified by resolving the requestor's DID?
  • PermissionsGrant implies that the capability is first stored in the grantor's hub before sending it to the requester
    • Will it be the case that PermissionsGrant also cannot require authorization? if not, will the requester provide the capability allowing the grantor to send a PermissionsGrant message to the requester's hub?
    • Does PermissionsGrant necessitate an associated PermissionsRequest? or can anyone just willy nilly PermissionsGrant bomb an Identity Hub?
  • PermissionsRevoke necessitates PermissionsQuery if PermissionsRevoke only accepts objectId
    • How is Alice to know the objectId beforehand otherwise? Unless the objectId is embedded in the capability itself

Criteria for selecting financial data Verifiable Credentials Issuers

When a user of TBDex wants to obtain financial data such as his account and routing number, transaction history or balance to apply for a loan or to buy or sell bitcoin an API that can provide the data automatically, without copy/paste error and signed as accurate is usually the preferred option.

When more than one option exists to obtain a VC with the required financial data the hub should select the provider without asking the user. This is to optimize the user experience (and because the user rarely has the information required to make an informed selection).

When more than one provider is available the selection criteria should be:

Privacy - Some providers resell the financial data or store it for long periods. Other providers are third parties (they are not the data source, but are intermediaries that screen scrape the data or call the data source’s API and then issue a VC) that must access the data on behalf of users, but are contractually obligated to delete the data and never reuse it.

Speed - Some services are faster than others and the speed can range from a few milliseconds to over 3 minutes among providers.

Cost - Some providers have an annual minimum payment in the tens of thousands of dollars with a per connection fee at over a dollar each. Other providers do not have annual minimums and charge only 1,000 satoshis per API call.

Accuracy - Financial data is often inaccurate or missing. For example obtaining the full account number more than 90% of the time or obtaining more than 90 days of transaction history is still a significant selling point among financial data providers as of 2022.

The identity hub reference implementation should include a simple algorithm to select a VC issuer. It should be easy to understand and modify to reflect their particular use cases and target users of a specific implementation.

One option is to assign an arbitrary number of points to privacy, speed, cost and accuracy that are then multiplied by the provider's score in each of these areas.

Let's call these priority points and assign an arbitrary value to each.

Default Priority Points:

Privacy - 12 priority points
Speed - 7 priority points
Cost - 14 priority points (with a maximum cap to default to 10,000 sats)
Accuracy - 9 priority points

This means that if provider A has excellent privacy but is very slow, cheap and accurate it would be awarded 12+0+14+9 = 34 points. If provider B has poor privacy, but is very fast, cheap and accurate it would be awarded 0+7+14+9 = 30 points. As a result provider A would be selected over provider B in this example.

Since providers are usually not either 100% good or bad in these areas we can assign them an arbitrary number of points based or their self reported behavior (although as with accuracy a better mechanism for obtaining this data should be considered an open work item):

Privacy:

Original data source without any third parties accessing the data - 100 privacy points.

Third party without access to credentials, with access to data but is contractually obligated to immediately destroy all copies - 90 privacy points.

Third party with access to credentials and data, but is contractually obligated to immediately destroy all copies - 80 privacy points.

Third party without access to credentials, with access to data and is not obligated to immediately destroy all copies - 30 privacy points.

Third party with access to credentials and data that is not obligated to to immediately destroy all copies - 0 privacy points

Speed:

0-10 seconds - 81 to 100 speed points

11-30 seconds - 80 to 61 speed points

31-90 seconds - 60 to 41 speed points

91-120 seconds - 40 to 11 speed points

121 - 200 seconds - 10-1 speed points

Over 200 seconds - 0 speed points

Cost:

0 - 1,000 sats 100 cost points

1,001 - 4,000 sats 60 cost points

4,001 - 10,000 sats 20 cost points

Over 10,000 sats - 0 cost points

Accuracy:

This is a difficult criteria because it is specific to a given financial institution and data field. For example a provider might retrieve the account number from Chase 99.999% of the time, but obtain the routing information only 10% of the time.

For now this can be treated as an open work item as initially there will not be many cases where more than one provider is available for a given financial institution and the subset where data accuracy would be the deciding factor is approaching zero, but the ideal solution is for wallets to report success rates over time so that they can be used to route requests.

Example Calculation

Let's assume provider A is a third party that does access user credentials and data, but is contractually obligated to delete all data (80 privacy points), will take 20 seconds to retrieve the data (70 speed points) and charges 1,000 sats (100 cost points).

To convert from privacy, speed and cost points to selection points we multiply the two numbers

Privacy - 12 priority points
Speed - 7 priority points
Cost - 14 priority points (with a maximum cap to default to 10,000 sats)

80 (privacy points) * 12 priority points = 960 selection points
70 (speed points) * 7 priority points = 490 selection points
100 (cost points) * 14 priority points = 1400 selection points

With a total of 2850 selection points provider A will be chosen when the alternative providers have fewer than 2850 selection points.

This was briefly discussed with @csuwildcat on a call last week.

Attestation field needs explanation

The example in Section 12.4.1 shows an attestation property under descriptor.ability.conditions that needs additional explanation to distinguish it from the top level attestation property.

Please change the name from "Identity Hub" to "Personal Data Store"

"Personal Data Store" is the long-standing industry term for this kind of thing. Please let's not invent a new term.

If people believe that the scope is wider than just "Personal", then use the name "Data Store". But please let's not unnecessarily create confusion by creating a new term. There's still time to correct this.

Remove the delegation property

message.descriptor.ability.conditions contains a delegate property, the intent of which is to prevent delegation of this capability. This feature is always a mistake. It prevents you from delegating a subset of the permissions in the capability to a program you run . Worse, it forces people to share credentials when delegating is important. The result is a system that is harder to use and less secure, all while losing the responsibility tracking provided by audit logs.

It is not unreasonable to use this property to specify conditions under which the delegator would prefer the capability not be delegated. For example, "delegate only to someone who has finished the training course," or "You may delegate to anyone from Ontario as long as the US is not at war with Canada."

These expressions imply a standard policy language, which is probably more than what people want here. Instead, remove the property completely or turn it into a "please do not delegate" preference. Delegating such a capability could require a plain text explanation of why the policy was violated.

Start with simple read only use cases and abstraction layers

I had a longer discussion with @expede and talked a bit to @csuwildcat about getting to a place of interop sooner rather than later rather than trying to "eat the whole elephant".

Between myself and @expede we'll do some work on figuring out how to write this up more fully, but it boils down into a couple of pieces.

  1. File Locations and Permissions based on a File Hierarchy Model

We're going to propose using identifiers that map to file paths, that should work for "static" on disk files or server paths, but also work essentially as arguments for permissions.

e.g. /Public/Apps/Blog/ is a way to ask for permission / access to everything in the Blog folder and below. /Public/Apps/Blog/somepost.md is access to a file.

I think @csuwildcat wants to see things like /Collection/Images to be somewhat standardized paths, which I think is useful to work towards. How to implement / execute / return such a query is up to each system, with the simplistic version being "files" at that location.

  1. Read access

Requesting read access to a public file hierarchy: it's public, so it's more about returning the location of these files to be able to be read (and possibly "relaying" them?)

Literally all projects should be able to complete this very basic interface so we get an early win -- a request is made for a file location, and all contents are returned.

Requesting encrypted read access: right at this stage we'll need to figure out key exchange and probably revocation, both of which are tricky.

I guess the next step is to "specify" this, can we put this up for discussion on next week's implementors agenda please.

I apologize for not being able to spend more time on this myself.

cc @carsonfarmer @oed

Use `nonce` instead of `timestamp`in "9.1 Last-Write Replace"

The use of timestamp in the DAG-JOSE header can be problematic. If a users computer has a miscsonfigured system clock they may end up with a timestamp that is in the future and it will be impossible to replace the object for a (long) while. Also, timestamp is not a registered header property in IANA. We could however use nonce where the highest nonce would always be the one that's selected to mitigate these issues.

Note: we do something similar in the suggested DID Publish stream type in Ceramic. We also use the URL property to indicate which object is being replaced.

Is encrypting file paths out of scope now?

Sorry if I'm rehashing a question that's already been resolved, I've not been following this work closely for awhile now. I just saw some discussion that raised the question in my mind from #76 and was wondering if file paths are going to be encrypted from the host or if this has been placed out of scope. By "host" I mean the computer that's operating the identity-hub software. So for example if I'm running my identity-hub in the cloud, do I need to trust my cloud provider in knowing which objects I have stored even if they can't see the data of the objects.

Individual messages don't have IDs

The spec doesn't indicate that individual messages have IDs. Only the request does.

  • Is this by design, if so, why?
  • Is message.descriptor.objectId the ID of the message?
  • can the message ID be deduced? e.g. CID of the entire message. If that's the case, why? what is lost by explicitly including it?

Request recipient is missing from request

The spec doesn't define how to identify the requester.

  • If this decision is intentional, why? might be useful to include the reasoning in the spec. I can think of scenarios where knowing who the requester is would be necessary (e.g. sending asynchronous responses)
  • I suppose it's possible to deduce the requester through authorization or attestation. Though, if that's the case, doesn't it become difficult to verify?

Revocation Subtleties

Revocation is a trickier subject than it first appears. Who has permission to revoke? What can be revoked with that permission? One point that is obvious but should be called out is that revoking a capability effectively revokes any capability delegated from it.

Can the delegatee revoke a capability it was given? There would seem to be no need; the delegatee can just not use the capability. However, it might be useful to prevent accidental use and to provide deniability if the delegatee can revoke its own capabilities.

Permission to revoke is implied by being on the delegation chain, but there are two possible interpretations of that permission. It could be only the next delegation on the chain or any downstream delegation. There are arguments for both.

Say that Alice delegates to Bob who delegates to Carol and to David. Bob might be unpleasantly surprised if Alice revokes Carol's capability. On the other hand, Alice might be in a position of responsibility and knows that Carol should not have the permission Bob granted to her, but Bob is unavailable to revoke Carol's capability. In that case, it is important to allow Alice to revoke Carol's capability without affecting David's.

These two cases could be policies implemented by different verifiers, but the capability itself might specify the desired policy.

Need to normatively define the service endpoint object for the DID Document

I was looking over the answer for #90 and realized we haven't defined the service endpoint object for an Identity Hub yet. This is an issue to track the item.

I believe an example would be the following:

{
  "service": [{
    "id":"did:example:123#identityHub",
    "type": "IdentityHub", 
    "serviceEndpoint": "https://hub.example.com/"
  }]
}

I remember @csuwildcat talking about awhile back that the serviceEndpoint may be an Array of URL endpoints rather than a single string. If that's the case we'll want to add details about that and the selection process for which one should be chosen and when as well I believe.

versioning of the spec

Could we please give commit 1f82822 a version (v0.1 for example) and publish it on a DIF website? Microsoft is using this specification in production and we would like to be able to refer our clients, etc. to one document. We thought that the specification is relatively stable since very few changes have been made, but looks like some non-backward compatible changes are being made, so as a compromise would really appreciate if we can version a commit above. Thanks!

Alias `@type` -> type

@type is a JSON-LD keyword, however to better meet the expectations of JSON consumers of Identity Hub related data objects you can choose in how you define your JSON-LD context to alias the @type field as type which effectively means the JSON-LD syntax sugar would collapse into a single @context entry.

Example the following

{
  "@context": "https://identity.foundation/schemas/hub",
  "@type": "FeatureDetectionRead"
}

Changes to

{
  "@context": "https://identity.foundation/schemas/hub",
  "type": "FeatureDetectionRead"
}

Message authorization signature in request object

Section 9 of the spec mentions:

The Message object MUST include a signature property, and its value MUST be a signature string produced by signing the payload value in Step 1

But the example JSON of a Request object shows:

{  // Request Object
  "requestId": "c5784162-84af-4aab-aff5-f1f8438dfc3d",
  "target": "did:example:123",
  "messages": [  // Message Objects
    {
      "data": BASE64_STRING,
      "descriptor": { ... },
      "attestation": { ... },
      "authorization": {
        "protected": { ... },
        "payload": CID(descriptor),
        "signature": Sign(protected + payload)
      }
    },
    {...}
  ]
}

In particular, this part: "signature": Sign(protected + payload)

Which one is it? Happy to create a PR.

Define and agree upon design goals

We need to specify design goals, and/or design and decision criteria, for Identity Hubs. These should comprehensively describe what is in or (more importantly) out of scope for Identity Hubs, and roughly how the in-scope items are organized.

I hope to make progress on the working group calls--this should certainly be a group decision, but I will self-assign to make sure someone is driving it forward.

Closes #60

Permissions Interface missing details

Ability

  • an ability MUST be represented as a JSON object that contains the following fields:
Field Required (Y/N)
method Y
schema N
objectId N
description N
  • an ability MUST contain the method field. all additional fields are optional and are used to further limit the scope of what the capability permits
  • the value * is reserved to represent all possible values for a given field
    • e.g. method: * can be interpreted as "All current and future available methods"
  • the fields within a capability are considered hierarchical. The hierarchy is as follows:
    method > schema > objectId
    
    • An ability that includes a specific field MUST include all cardinal fields.
      • e.g. a capability that includes objectId MUST include schema and method
    • any omitted subsidiary fields within a capability are implicitly represented as field: *
      • e.g. { "method": "CollectionsWrite" } is equivalent to { "method": "CollectionsWrite", schema: "*", "objectId": "*" }

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.