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

Make cuid2 available in @default #17102

Open
Yiak opened this issue Jan 2, 2023 · 53 comments
Open

Make cuid2 available in @default #17102

Yiak opened this issue Jan 2, 2023 · 53 comments
Labels
kind/feature A request for a new feature. team/client Issue for team Client. team/schema Issue for team Schema. tech/engines Issue for tech Engines. topic: cuid topic: default

Comments

@Yiak
Copy link

Yiak commented Jan 2, 2023

Problem

cuid() is deprecated now due to security reasons, can we let cuid2 be an option when generating ids?

@jkomyno jkomyno added kind/feature A request for a new feature. team/schema Issue for team Schema. process/candidate topic: cuid labels Jan 3, 2023
@magoz
Copy link

magoz commented Jan 8, 2023

Also interested in this. Any plans?

@Jolg42
Copy link
Member

Jolg42 commented Jan 9, 2023

Hello!
Where did you find the news? Just curious on how you found out about cuid being deprecated, it looks like this is only one week old to me.

Notes:

The JS package says https://github.com/paralleldrive/cuid

Status: Deprecated due to security. Use Cuid2, instead.
Note: All monotonically increasing (auto-increment), and timestamp-based ids share the security issues with Cuid. V4 UUIDs and GUIDs are also insecure because it’s possible to predict future values of many random algorithms, and many of them are biased, leading to increased probability of collision.

Prisma actually uses the Rust version https://crates.io/crates/cuid (based on the JS lib) which doesn't have a replacement for now:
mplanchard/cuid-rust#4

@Jolg42
Copy link
Member

Jolg42 commented Jan 9, 2023

Notes:
It looks like we were using the cuid npm package, but only for generating a random if for our test setup.
It will be removed in #17200

After that, the only version we use is https://crates.io/crates/cuid in prisma-engines
https://github.com/search?q=repo%3Aprisma%2Fprisma-engines+cuid+language%3ATOML&type=code&l=TOML

@Jolg42
Copy link
Member

Jolg42 commented Jan 18, 2023

Note: the Rust author of the cuid create wants to add support for cuid2 in the crate 💚 . Let's check back once it's done.

@magoz
Copy link

magoz commented Jan 20, 2023

That's awesome, @Jolg42! Thanks

@Jolg42 Jolg42 added the tech/engines Issue for tech Engines. label Jan 20, 2023
@cupcakearmy
Copy link

Seems like the first release dropped https://crates.io/crates/cuid2

@immjs
Copy link

immjs commented Jan 26, 2023

Has it been changed yet?

@Jolg42
Copy link
Member

Jolg42 commented Jan 26, 2023

https://github.com/mplanchard/cuid-rust

The cuid2 crate has been published to crates.io, at version 0.1.0 (not quite ready to commit to API stability yet, but will soon!)

All cuid v1 functions in the cuid crate have been marked as deprecated, and a new cuid2() function has been added.

Originally posted by @mplanchard in mplanchard/cuid-rust#4 (comment)

@Yedidya10
Copy link

Hi. I have not been able to fully understand what has developed so far. Is it safe to use @default(cuid()) even though it is deprecated?

@mplanchard
Copy link

mplanchard commented Feb 23, 2023 via email

@mplanchard
Copy link

Regarding the deprecation, I don't know the position of the Prisma team, but the position of the author of cuid and cuid2 is that folks should move to cuid2 as soon as they're able to. My personal opinion is that the rust port of the original cuid algorithm doesn't suffer from some of the issues that affected the reference implementation (portability and variable length), but the new version is more collision resistant, so it's still good to migrate when possible.

@kevinvdburgt
Copy link

Any workarounds available to already use cuid2 with the current release of prisma?

@ciscoheat
Copy link

@kevinvdburgt You can always remove the @default attribute and use the cuid2 library to add them yourself for the fields in question, it's not too much of a hassle.

@rothlis
Copy link

rothlis commented Feb 27, 2023

@kevinvdburgt You can always remove the @default attribute and use the cuid2 library to add them yourself for the fields in question, it's not too much of a hassle.

This and we have used a Prisma middleware to generate cuid2 ids.

@ciscoheat
Copy link

Ah yes, a middleware should be the best solution.

@413n
Copy link

413n commented Feb 27, 2023

This and we have used a Prisma middleware to generate cuid2 ids.

@rothlis Could you provide a snippet of the middleware?

@rothlis
Copy link

rothlis commented Feb 27, 2023

It would look something like this:

prisma.$use(async (params, next) => {
  if (params.action === "create") {
    params.args.data.id ??= createId()
  }
  return next(params)
})

You can also filter/exclude specific models with params.model (see docs). For example, we use Next-Auth with Prisma and we only target Next-Auth's models as we generate our ids in code.

@ciscoheat
Copy link

Remember to handle createMany as well. Maybe we should do a little community effort to make a snippet like this? As a gist?

@jpmelnik
Copy link

jpmelnik commented Mar 5, 2023

I'm trying a Middleware approach but validation with ZOD z.string().cuid2() didn't pass.

Is any extra configuration necessary?

@keeandev
Copy link

What's the status of this implementation? cuid2 has been deprecated for a couple of months and has clearly stated that it has security vulnerabilities. No harsh feelings toward the Prisma team!

@ari-becker
Copy link

@Vashiru I'm not involved in this, so I don't have the context myself to drive the discussion.

One concern I remember being raised is the length of cuid strings. Is it the same between cuid 1 and 2? Prisma users may have designed their database schema (e.g. fixed length string columns) around that, so we have to be sure we won't break them.

@tomhoule is there a reason why Prisma couldn't just add cuid2() as a separate function for default(), while deprecating (but not removing) cuid()? This makes cuid2 available for new users and for users willing to make the time to migrate, while not affecting existing schemas. I don't understand why this needs to be an either/or decision, why not both?

@janpio janpio changed the title Make cuid2 available in @default Make cuid2 available in @default May 18, 2023
@llravelo
Copy link

llravelo commented Jun 7, 2023

Looking forward to a native cuid2() implementation!

@stefanwimmer128
Copy link

Also looking forward to a native implementation.

PS: For all interest: I wrote a easily configurable prisma middleware to do this in the interim. (https://git.stefanwimmer128.io/-/snippets/7)

@benjamin-guibert
Copy link

Hello, I am not sure to follow: is cuid() still using the v1 today? Should we still use the workaround in order to use the v2?

@llravelo
Copy link

@benjamin-guibert Prisma still uses v1, but there are a number of workarounds suggested in this thread.

@benjamin-guibert
Copy link

Thank you @llravelo. Isn't it as critical as it sounds, the security concern? I'm trying to understand why this is not a priority (6 months old). 🤔

@janhesters
Copy link

janhesters commented Jul 16, 2023

@Jolg42

Note: the Rust author of the cuid create wants to add support for cuid2 in the crate 💚 . Let's check back once it's done.

The crate has since been published and is stable 😊👍

https://crates.io/crates/cuid2/

@reubenporterjisc
Copy link

Hi, any updates on whether this will be added into prisma when using cuid() to generate ids?

@fbele
Copy link

fbele commented Aug 2, 2023

A small workaround in the mean time using the new $extends API:

import { PrismaClient } from "@prisma/client";
import { createId } from "@paralleldrive/cuid2";

const prisma = new PrismaClient();

const xprisma = prisma.$extends({
    query: {
        user: {
            async create({ model, operation, args, query }) {
                args.data.id = createId();
                
                return query(args)
            },
            async createMany({ model, operation, args, query }) {
                if (Array.isArray(args.data)) {
                    args.data.map((user) => user.id = createId());
                } else {
                    args.data.id = createId();
                }
                
                return query(args)
            },
        },
    },
});

From then on you need to use for example xprisma.user.create() because this is the extended instance of the Prisma Client.
Hope it helps anyone.

@jitterbux
Copy link

Any news on CUID2?

@reubenporterjisc
Copy link

Hi, any updates on this? If this was built into Prisma it would save all of the manual workarounds. Thanks!

@njoshi22
Copy link

OK I'm surprised this is still open - any updates here?

@kakarot-dev
Copy link

Why is this still not implemented?

@demsey2
Copy link

demsey2 commented Nov 19, 2023

2.9K issues, 168 PRs, they must have some issue with people/projects management

@cryptrr
Copy link

cryptrr commented Dec 5, 2023

I think there might be some performance considerations in moving away from sequential K-Sortable ids like cuid v1 or uuid.

cuid v2 isn't K-Sortable and is also harder to cursor paginate.

@DePasqualeOrg
Copy link
Contributor

I think there might be some performance considerations in moving away from sequential K-Sortable ids like cuid v1 or uuid.

cuid v2 isn't K-Sortable and is also harder to cursor paginate.

See the section on performance here:

https://github.com/paralleldrive/cuid2#note-on-k-sortablesequentialmonotonically-increasing-ids

TL;DR: Stop worrying about K-Sortable ids. They're not a big deal anymore. Use createdAt fields instead.

@asineth0
Copy link

asineth0 commented Dec 6, 2023

This issue has been open for an entire year? Shouldn't implementing a cuid2() function be pretty straightforward?

Anyway, the entire "CUID is insecure!" point is arguably misleading and wrong. CUID was designed as a chronologically sortable ID, if you didn't want that then use UUID instead. I doubt anyone is using CUID for password reset tokens (one of their examples of what it's "insecure"), so that just seems wild to me.

I just went back to using UUIDs.

@cyrilchapon
Copy link

cyrilchapon commented Feb 1, 2024

Surprisingly, am I the only one here with the exact same requirement; but different use-case ? ☺️

Cuid2 tend to have another strong advantage against cuid1 : configurable length. I'm in a situation where I'd love to (voluntarily) reduce the collision-safety and the ids length; just for the pleasure to have short ids.

Thus, I just would love to be able to :

  id  String  @id @default(cuid2(length: 10))

@sooxt98
Copy link

sooxt98 commented Feb 10, 2024

I can see there's a half baked prisma cuid2 PR that doesn't support custom length and fingerprint yet
prisma/prisma-engines#4218

@nrdobie
Copy link

nrdobie commented Feb 16, 2024

I have made a slightly more improved version of the extension that will automatically apply to all models without having to continuously update the extension.

https://gist.github.com/nrdobie/c8255815b0083acf98be3e84bfd7c8a8

import { createId } from "@paralleldrive/cuid2";
import { Prisma } from "@prisma/client";
import { produce } from "immer";

const cuid2Extension = Prisma.defineExtension({
  name: "cuid2",
  query: {
    $allModels: {
      create({ query, args }) {
        const argsWithNewId = produce(args, (draft) => {
          if (!draft.data.id) {
            draft.data.id = createId();
          }
        });

        return query(argsWithNewId);
      },
      createMany({ query, args }) {
        const argsWithNewIds = produce(args, (draft) => {
          if (Array.isArray(draft.data)) {
            draft.data = draft.data.map((item) => {
              if (!item.id) {
                item.id = createId();
              }

              return item;
            }) as typeof draft.data;
          } else {
            if (draft.data.id) {
              draft.data.id = createId();
            }
          }
        });

        return query(argsWithNewIds);
      },
    },
  },
});

export default cuid2Extension;

@thomasfr
Copy link

Any updates or ETA on CUID2 support for Prisma?

@nrdobie
Copy link

nrdobie commented Feb 23, 2024

I converted my solution into a package to make it easier to use CUID2 with Prisma. I am willing to add additional features if people need some extra complexity.

prisma-extension-cuid2

@Sczlog
Copy link

Sczlog commented Mar 13, 2024

I think there might be some performance considerations in moving away from sequential K-Sortable ids like cuid v1 or uuid.
cuid v2 isn't K-Sortable and is also harder to cursor paginate.

See the section on performance here:

https://github.com/paralleldrive/cuid2#note-on-k-sortablesequentialmonotonically-increasing-ids

TL;DR: Stop worrying about K-Sortable ids. They're not a big deal anymore. Use createdAt fields instead.

createdAt is not a good choice for cursor as it is not unique

@dever23b
Copy link

I think there might be some performance considerations in moving away from sequential K-Sortable ids like cuid v1 or uuid.
cuid v2 isn't K-Sortable and is also harder to cursor paginate.

See the section on performance here:

https://github.com/paralleldrive/cuid2#note-on-k-sortablesequentialmonotonically-increasing-ids

TL;DR: Stop worrying about K-Sortable ids. They're not a big deal anymore. Use createdAt fields instead.

createdAt is not a good choice for cursor as it is not unique

Unless I'm misunderstanding you, I think the solution for your concern is to pull the (non-sortable) ID in the result fieldset, sorted by createdAt, and use the ID as the cursor to continue pagination.

Forgive me if I'm writing the right answer to the wrong question. But I believe much of the concern about sortable IDs resolves down to when those IDs are public and can be referenced externally (because then bad actors can guess IDs and potentially access out of scope data). One potential solution, if you absolutely must use sortable IDs, is to store multiple IDs and keep the sortable IDs private from ever being displayed to users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature A request for a new feature. team/client Issue for team Client. team/schema Issue for team Schema. tech/engines Issue for tech Engines. topic: cuid topic: default
Projects
None yet
Development

No branches or pull requests