DevelopingSpace / starchart

A self-serve tool for managing custom domains and certificates
MIT License
21 stars 13 forks source link

Crash: Argument username: Got invalid value {} on prisma.findUniqueUser. Provided Json, expected String #500

Closed humphd closed 1 year ago

humphd commented 1 year ago

Testing login on staging, and I am crashing:

STR:

  1. go to https://mycustomdomain-dev.senecacollege.ca/
  2. login
  3. landing page shows (seems to work)
  4. click the Refresh button
  5. crash
Error: Argument username: Got invalid value {} on prisma.findUniqueUser. Provided Json, expected String.

    at ti.validate (/app/node_modules/@prisma/client/runtime/library.js:149:91)
    at Wr.createMessage (/app/node_modules/@prisma/client/runtime/library.js:164:13655)
    at /app/node_modules/@prisma/client/runtime/library.js:174:10933
    at runInChildSpan (/app/node_modules/@prisma/client/runtime/library.js:70:25817)
    at t._executeRequest (/app/node_modules/@prisma/client/runtime/library.js:174:10922)

cc @sfrunza13

humphd commented 1 year ago

I also get this, which might be due to the error UI, not sure:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-fce57198ab4ec4626f3a32dafeb3710d'". Either the 'unsafe-inline' keyword, a hash ('sha256-0KqKcnhVQ7L1UQiSsKJtbNecZ8HT4jOPE0ZcanKImi0='), or a nonce ('nonce-...') is required to enable inline execution.
humphd commented 1 year ago

I can reproduce locally, and the error is better:

Error: 
Invalid `prisma.user.findUnique()` invocation in
/Users/humphd/repos/starchart/app/models/user.server.ts:15:34

  12 }
  13 
  14 export async function getUserByUsername(username: PrismaUser['username']) {
→ 15   const user = await prisma.user.findUnique({
         where: {
           username: {}
           ~~~~~~~~
         }
       })

Argument username: Got invalid value {} on prisma.findUniqueUser. Provided Json, expected String.

    at ti.validate (/Users/humphd/repos/starchart/build/server.js:129682:35)
    at Wr.createMessage (/Users/humphd/repos/starchart/build/server.js:130602:18)
    at /Users/humphd/repos/starchart/build/server.js:131506:41
    at runInChildSpan (/Users/humphd/repos/starchart/build/server.js:128471:16)
    at t._executeRequest (/Users/humphd/repos/starchart/build/server.js:131506:27)
sfrunza13 commented 1 year ago

I do not encounter it on staging, but I can reproduce it using the admin account locally. It's probably something I just did.

humphd commented 1 year ago

Locally, it looks like the value coming back from getEffectiveUsername is the issue:

export async function getEffectiveUsername(
  request: Request
): Promise<User['username'] | undefined> {
  const cookie = request.headers.get('Cookie');
  const effectiveUsername = await effectiveUsernameCookie.parse(cookie);
  console.log('got effectiveUsername', effectiveUsername);
  return effectiveUsername as User['username'];
}

Gives this (note the {}):

getEffectiveUsername { username: 'han.solo', effectiveUsername: {} }
Trace: got bad username {}
    at getUserByUsername (/Users/humphd/repos/starchart/app/models/user.server.ts:15:34)
    at getEffectiveUser (/Users/humphd/repos/starchart/app/session.server.ts:77:12)
    at loader (/Users/humphd/repos/starchart/app/root.tsx:44:20)
    at Object.callRouteLoaderRR (/Users/humphd/repos/starchart/build/server.js:37990:20)
    at callLoaderOrAction (/Users/humphd/repos/starchart/build/server.js:37099:18)
    at async Promise.all (index 0)
    at loadRouteData (/Users/humphd/repos/starchart/build/server.js:36889:23)
    at queryImpl (/Users/humphd/repos/starchart/build/server.js:36756:24)
    at Object.query (/Users/humphd/repos/starchart/build/server.js:36690:22)
    at handleDocumentRequestRR (/Users/humphd/repos/starchart/build/server.js:38264:19)
humphd commented 1 year ago

Deep in the Remix code, they do this on the cookie when you call .parse():

async function decodeCookieValue(
  unsign: UnsignFunction,
  value: string,
  secrets: string[]
): Promise<any> {
  if (secrets.length > 0) {
    for (let secret of secrets) {
      let unsignedValue = await unsign(value, secret);
      if (unsignedValue !== false) {
        return decodeData(unsignedValue);
      }
    }

    return null;
  }

  return decodeData(value);
}

function encodeData(value: any): string {
  return btoa(myUnescape(encodeURIComponent(JSON.stringify(value))));
}

function decodeData(value: string): any {
  try {
    return JSON.parse(decodeURIComponent(myEscape(atob(value))));
  } catch (error: unknown) {
    return {};                            <------- I wonder if this is what we're getting back for some reason?
  }
}
humphd commented 1 year ago

Yes, it is, I added a log and got this on that error:

SyntaxError: "undefined" is not valid JSON
    at JSON.parse (<anonymous>)
    at decodeData (/Users/humphd/repos/starchart/node_modules/@remix-run/server-runtime/dist/cookies.js:96:17)
    at decodeCookieValue (/Users/humphd/repos/starchart/node_modules/@remix-run/server-runtime/dist/cookies.js:89:10)
    at Object.parse (/Users/humphd/repos/starchart/node_modules/@remix-run/server-runtime/dist/cookies.js:54:66)
    at getEffectiveUsername (/Users/humphd/repos/starchart/app/session.server.ts:52:59)
    at requireUsername (/Users/humphd/repos/starchart/app/session.server.ts:119:5)
    at loader9 (/Users/humphd/repos/starchart/app/routes/__index/index.tsx:9:26)
    at Object.callRouteLoaderRR (/Users/humphd/repos/starchart/build/server.js:37991:26)
    at commonRoute.loader (/Users/humphd/repos/starchart/build/server.js:38063:56)
    at callLoaderOrAction (/Users/humphd/repos/starchart/build/server.js:37100:38)

So we're putting undefined into the Cookie?

sfrunza13 commented 1 year ago

yeah, sorry. I was putting the empty string there before.

humphd commented 1 year ago

null is valid JSON, can we use that instead?

sfrunza13 commented 1 year ago

501 works with the local admin