stephenou / fruitionsite

Build your website with Notion for free
https://fruitionsite.com
MIT License
1.6k stars 223 forks source link

Notion Ask to Login after tapping Back button #237

Open jevanjovandy opened 1 year ago

jevanjovandy commented 1 year ago

Notion asking to Login after Back button tapped. I think this comes from Notion changing 'www.notion.so' to 'yoursite.notion.site'. Anyone already have a solution to this problem? Thanks before.

image

JustSleightly commented 1 year ago

+1 I have also started noticing this more recently within the last week on my own notion

eeshabarua commented 1 year ago

+1 I'm having the same issue.

JackyGohSG commented 1 year ago

+1

smugfox commented 1 year ago

+1

DudeThatsErin commented 1 year ago

+1

melihcelenk commented 1 year ago

+1

jruers commented 1 year ago

+1

gojomo commented 1 year ago

Notably, when checking sites in the Fruition-users 'Showcase' https://stephenou.notion.site/92053970e5084019ac096d2df7e7f440?v=2bed11f9a95d41f59e8af11a7746c339, even if the page content is displaying, it's coming back as an HTTP 404 error (prompting some browsers to display an extra error-banner), and navigating forward to subpages works, but backing-up lands on the Notion sign-up page.

eeshabarua commented 1 year ago

I resolved the issue!! Please try and see if this resolves it for you.

Chrome Dev Tools Console was displaying the following error messages:

To Solve: Modify the Cloudflare Worker worker.js code to handle the redirection and serving of Notion pages based on slugs. The worker should receive incoming requests and serve the appropriate content based on the slug-to-page mapping without relying on client-side JavaScript for redirection.

  1. Update fetchAndApply() to correctly handle the soft navigation (see code below):

The new block detects if the user is trying to access a Notion page using a slug, and if so, it redirects the user to the corresponding Notion page instead of client-side JavaScript (which is a Notion endpoint and therefore would have needed reauthentication.)

  1. Update domain name in the Worker file (as solved in #236 )
  2. Clear cached browsing data to avoid the origin and BaseURL Mismatch error (as solved in #122)
async function fetchAndApply(request) {
  if (request.method === 'OPTIONS') {
    return handleOptions(request);
  }
  let url = new URL(request.url);
  url.hostname = 'eeshabarua.notion.site';
  if (url.pathname === '/robots.txt') {
    return new Response('Sitemap: https://' + MY_DOMAIN + '/sitemap.xml');
  }
  if (url.pathname === '/sitemap.xml') {
    let response = new Response(generateSitemap());
    response.headers.set('content-type', 'application/xml');
    return response;
  }
  let response;
  if (url.pathname.startsWith('/app') && url.pathname.endsWith('js')) {
    response = await fetch(url.toString());
    let body = await response.text();
    response = new Response(body.replace(/eeshabarua.notion.site/g, MY_DOMAIN).replace(/notion.so/g, MY_DOMAIN), response);
    response.headers.set('Content-Type', 'application/x-javascript');
    return response;
  } else if ((url.pathname.startsWith('/api'))) {
    // Forward API
    response = await fetch(url.toString(), {
      body: url.pathname.startsWith('/api/v3/getPublicPageData') ? null : request.body,
      headers: {
        'content-type': 'application/json;charset=UTF-8',
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
      },
      method: 'POST',
    });
    response = new Response(response.body, response);
    response.headers.set('Access-Control-Allow-Origin', '*');
    return response;
  } else {
    const currentSlug = url.pathname.slice(1);
    const pageId = SLUG_TO_PAGE[currentSlug];

    if (pageId) {
      const notionUrl = `https://eeshabarua.notion.site/${pageId.replace(/-/g, '')}`;
      return Response.redirect(notionUrl, 301);
    }

    response = await fetch(url.toString(), {
      body: request.body,
      headers: request.headers,
      method: request.method,
    });
    response = new Response(response.body, response);
    response.headers.delete('Content-Security-Policy');
    response.headers.delete('X-Content-Security-Policy');

    // Soft navigation handling
    if (slugs.indexOf(currentSlug) > -1) {
      const destinationPageId = SLUG_TO_PAGE[currentSlug];
      if (destinationPageId) {
        const notionUrl = `https://eeshabarua.notion.site/${destinationPageId.replace(/-/g, '')}`;
        const { pathname, search, hash } = new URL(notionUrl);
        const redirectUrl = `${MY_DOMAIN}/${currentSlug}${search}${hash}`;
        response.headers.set('Content-Type', 'text/html');
        response.headers.set('Cache-Control', 'no-store');
        response.headers.set('Location', redirectUrl);
        response.status = 302;
        return response;
      }
    }

    return appendJavascript(response, SLUG_TO_PAGE);
  }
}
jruers commented 1 year ago

hi @eeshabarua , do not get to work it. Replaced the part with yours and of course changed eeshabarua.... But not working.

eeshabarua commented 1 year ago

@jruers Hmm... can you describe the behavior? Is the back button still prompting reauth?

jruers commented 1 year ago

Maybe I replace something wrong, but the notion site is not found after I adjusted the worker...

eeshabarua commented 1 year ago

I apologize, the code block I provided still had notion.so URL instead of yoursite.notion.site. It is now edited to reflect those changes.

Here is my full worker.js if for debugging purposes.

// CONFIGURATION STARTS HERE

// Step 1: enter your domain name like fruitionsite.com
const MY_DOMAIN = 'eeshabarua.me';

/*
 * Step 2: enter your URL slug to page ID mapping
 * The key on the left is the slug (without the slash)
 * The value on the right is the Notion page ID
 */
const SLUG_TO_PAGE = {
  '': '506b6a6b6ac94378ba32764d4b09f27a',
};

// CONFIGURATION ENDS HERE

const PAGE_TO_SLUG = {};
const slugs = [];
const pages = [];
Object.keys(SLUG_TO_PAGE).forEach(slug => {
  const page = SLUG_TO_PAGE[slug];
  slugs.push(slug);
  pages.push(page);
  PAGE_TO_SLUG[page] = slug;
});

addEventListener('fetch', event => {
  event.respondWith(fetchAndApply(event.request));
});

function generateSitemap() {
  let sitemap = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
  slugs.forEach(
    (slug) =>
    (sitemap +=
      '<url><loc>https://' + MY_DOMAIN + '/' + slug + '</loc></url>')
  );
  sitemap += '</urlset>';
  return sitemap;
}

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
};

function handleOptions(request) {
  if (request.headers.get('Origin') !== null &&
    request.headers.get('Access-Control-Request-Method') !== null &&
    request.headers.get('Access-Control-Request-Headers') !== null) {
    // Handle CORS pre-flight request.
    return new Response(null, {
      headers: corsHeaders
    });
  } else {
    // Handle standard OPTIONS request.
    return new Response(null, {
      headers: {
        'Allow': 'GET, HEAD, POST, PUT, OPTIONS',
      }
    });
  }
}

async function fetchAndApply(request) {
  if (request.method === 'OPTIONS') {
    return handleOptions(request);
  }
  let url = new URL(request.url);
  url.hostname = 'eeshabarua.notion.site';
  if (url.pathname === '/robots.txt') {
    return new Response('Sitemap: https://' + MY_DOMAIN + '/sitemap.xml');
  }
  if (url.pathname === '/sitemap.xml') {
    let response = new Response(generateSitemap());
    response.headers.set('content-type', 'application/xml');
    return response;
  }
  let response;
  if (url.pathname.startsWith('/app') && url.pathname.endsWith('js')) {
    response = await fetch(url.toString());
    let body = await response.text();
    response = new Response(body.replace(/eeshabarua.notion.site/g, MY_DOMAIN).replace(/notion.so/g, MY_DOMAIN), response);
    response.headers.set('Content-Type', 'application/x-javascript');
    return response;
  } else if ((url.pathname.startsWith('/api'))) {
    // Forward API
    response = await fetch(url.toString(), {
      body: url.pathname.startsWith('/api/v3/getPublicPageData') ? null : request.body,
      headers: {
        'content-type': 'application/json;charset=UTF-8',
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
      },
      method: 'POST',
    });
    response = new Response(response.body, response);
    response.headers.set('Access-Control-Allow-Origin', '*');
    return response;
  } else {
    const currentSlug = url.pathname.slice(1);
    const pageId = SLUG_TO_PAGE[currentSlug];

    if (pageId) {
      const notionUrl = `https://eeshabarua.notion.site/${pageId.replace(/-/g, '')}`;
      return Response.redirect(notionUrl, 301);
    }

    response = await fetch(url.toString(), {
      body: request.body,
      headers: request.headers,
      method: request.method,
    });
    response = new Response(response.body, response);
    response.headers.delete('Content-Security-Policy');
    response.headers.delete('X-Content-Security-Policy');

    // Soft navigation handling
    if (slugs.indexOf(currentSlug) > -1) {
      const destinationPageId = SLUG_TO_PAGE[currentSlug];
      if (destinationPageId) {
        const notionUrl = `https://eeshabarua.notion.site/${destinationPageId.replace(/-/g, '')}`;
        const { pathname, search, hash } = new URL(notionUrl);
        const redirectUrl = `${MY_DOMAIN}/${currentSlug}${search}${hash}`;
        response.headers.set('Content-Type', 'text/html');
        response.headers.set('Cache-Control', 'no-store');
        response.headers.set('Location', redirectUrl);
        response.status = 302;
        return response;
      }
    }

    return appendJavascript(response, SLUG_TO_PAGE);
  }
}

class MetaRewriter {
  element(element) {
    // Modify meta tags for SEO if needed
  }
}

class HeadRewriter {
  element(element) {
    // Modify head content if needed, e.g., adding custom styles, scripts, or fonts
  }
}

class BodyRewriter {
  constructor(SLUG_TO_PAGE) {
    this.SLUG_TO_PAGE = SLUG_TO_PAGE;
  }

  element(element) {
    // Modify body content if needed
  }
}

async function appendJavascript(res, SLUG_TO_PAGE) {
  return new HTMLRewriter()
    .on('title', new MetaRewriter())
    .on('meta', new MetaRewriter())
    .on('head', new HeadRewriter())
    .on('body', new BodyRewriter(SLUG_TO_PAGE))
    .transform(res);
}
jruers commented 1 year ago

@eeshabarua tried your worker... still prompting reauth

JustSleightly commented 1 year ago

After implementing this fix for another issue for fruition, my issue here seems to also have resolved itself.

bryange3 commented 1 year ago

Worked for me, thanks Eesha!

bflack commented 1 year ago

Dark/light fix also worked for me. The earlier one forwarded to my actual notion URL instead of my vanity URL so no-go there.

tamagamis commented 1 year ago

@gojomo @jevanjovandy Currently the source code is outdated, it will have to be updated, I have a functional one that I will publish soon. (maybe in the pull or in this section) the errors are as mentioned ca Domain changes, script, cloudflare worker .

angadsri commented 1 year ago

I resolved the issue!! Please try and see if this resolves it for you.

Thanks for sharing your fix, @eeshabarua! It did sort out the problem for me, though it seems that when I change the code it also messes up my 'pretty' URLs, which start displaying as *****.notion.site

After implementing this fix for another issue for fruition, my issue here seems to also have resolved itself.

It's so lucky you tried this fix already, @JustSleightly, thanks for sharing! This dark/light mode code change actually somehow did fix the back-login problem for me too.

Appreciate this community!

mbochynski commented 1 year ago

@olimpa Any update on your update? :D The dark/light fix worked for me, but I don't like the reloading part.

EDIT: I've just tested the dark/light solution without window.location.reload(); line and it works perfectly fine to me.   🤔

DudeThatsErin commented 1 year ago

@jruers Hmm... can you describe the behavior? Is the back button still prompting reauth?

I was using the previous code wrong but it isn't working.

  // CONFIGURATION STARTS HERE

// Step 1: enter your domain name like fruitionsite.com
const MY_DOMAIN = 'codinghelp.site';

/*
 * Step 2: enter your URL slug to page ID mapping
 * The key on the left is the slug (without the slash)
 * The value on the right is the Notion page ID
 */
const SLUG_TO_PAGE = {
  '': '4c97396d18034520bf450b7d7485a4c4?pvs=4',
};

// CONFIGURATION ENDS HERE

const PAGE_TO_SLUG = {};
const slugs = [];
const pages = [];
Object.keys(SLUG_TO_PAGE).forEach(slug => {
  const page = SLUG_TO_PAGE[slug];
  slugs.push(slug);
  pages.push(page);
  PAGE_TO_SLUG[page] = slug;
});

addEventListener('fetch', event => {
  event.respondWith(fetchAndApply(event.request));
});

function generateSitemap() {
  let sitemap = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
  slugs.forEach(
    (slug) =>
    (sitemap +=
      '<url><loc>https://' + MY_DOMAIN + '/' + slug + '</loc></url>')
  );
  sitemap += '</urlset>';
  return sitemap;
}

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
};

function handleOptions(request) {
  if (request.headers.get('Origin') !== null &&
    request.headers.get('Access-Control-Request-Method') !== null &&
    request.headers.get('Access-Control-Request-Headers') !== null) {
    // Handle CORS pre-flight request.
    return new Response(null, {
      headers: corsHeaders
    });
  } else {
    // Handle standard OPTIONS request.
    return new Response(null, {
      headers: {
        'Allow': 'GET, HEAD, POST, PUT, OPTIONS',
      }
    });
  }
}

async function fetchAndApply(request) {
  if (request.method === 'OPTIONS') {
    return handleOptions(request);
  }
  let url = new URL(request.url);
  url.hostname = 'dudethatserin.notion.site';
  if (url.pathname === '/robots.txt') {
    return new Response('Sitemap: https://' + MY_DOMAIN + '/sitemap.xml');
  }
  if (url.pathname === '/sitemap.xml') {
    let response = new Response(generateSitemap());
    response.headers.set('content-type', 'application/xml');
    return response;
  }
  let response;
  if (url.pathname.startsWith('/app') && url.pathname.endsWith('js')) {
    response = await fetch(url.toString());
    let body = await response.text();
    response = new Response(body.replace(/dudethatserin.notion.site/g, MY_DOMAIN).replace(/notion.so/g, MY_DOMAIN), response);
    response.headers.set('Content-Type', 'application/x-javascript');
    return response;
  } else if ((url.pathname.startsWith('/api'))) {
    // Forward API
    response = await fetch(url.toString(), {
      body: url.pathname.startsWith('/api/v3/getPublicPageData') ? null : request.body,
      headers: {
        'content-type': 'application/json;charset=UTF-8',
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
      },
      method: 'POST',
    });
    response = new Response(response.body, response);
    response.headers.set('Access-Control-Allow-Origin', '*');
    return response;
  } else {
    const currentSlug = url.pathname.slice(1);
    const pageId = SLUG_TO_PAGE[currentSlug];

    if (pageId) {
      const notionUrl = `https://dudethatserin.notion.site/${pageId.replace(/-/g, '')}`;
      return Response.redirect(notionUrl, 301);
    }

    response = await fetch(url.toString(), {
      body: request.body,
      headers: request.headers,
      method: request.method,
    });
    response = new Response(response.body, response);
    response.headers.delete('Content-Security-Policy');
    response.headers.delete('X-Content-Security-Policy');

    // Soft navigation handling
    if (slugs.indexOf(currentSlug) > -1) {
      const destinationPageId = SLUG_TO_PAGE[currentSlug];
      if (destinationPageId) {
        const notionUrl = `https://dudethatserin.notion.site/${destinationPageId.replace(/-/g, '')}`;
        const { pathname, search, hash } = new URL(notionUrl);
        const redirectUrl = `${MY_DOMAIN}/${currentSlug}${search}${hash}`;
        response.headers.set('Content-Type', 'text/html');
        response.headers.set('Cache-Control', 'no-store');
        response.headers.set('Location', redirectUrl);
        response.status = 302;
        return response;
      }
    }

    return appendJavascript(response, SLUG_TO_PAGE);
  }
}

class MetaRewriter {
  element(element) {
    // Modify meta tags for SEO if needed
  }
}

class HeadRewriter {
  element(element) {
    // Modify head content if needed, e.g., adding custom styles, scripts, or fonts
  }
}

class BodyRewriter {
  constructor(SLUG_TO_PAGE) {
    this.SLUG_TO_PAGE = SLUG_TO_PAGE;
  }

  element(element) {
    // Modify body content if needed
  }
}

async function appendJavascript(res, SLUG_TO_PAGE) {
  return new HTMLRewriter()
    .on('title', new MetaRewriter())
    .on('meta', new MetaRewriter())
    .on('head', new HeadRewriter())
    .on('body', new BodyRewriter(SLUG_TO_PAGE))
    .transform(res);
}

I keep getting some kind of mismatch. image image

adhinugrahasaputra commented 11 months ago

My website is imamhanafi.com , I have used the script above but it is not working. can anyone help why?

blankbro commented 9 months ago

I seem to have resolved the issue of requesting login after clicking the back button. You can go to my website (blankbro.site) to try it out. My solution is to annotate the following code ↓↓↓

// const open = window.XMLHttpRequest.prototype.open;
// window.XMLHttpRequest.prototype.open = function() {
//   arguments[1] = arguments[1].replace('${MY_DOMAIN}', 'www.notion.so');
//   return open.apply(this, [].slice.call(arguments));
// };

good luck 🎉

wihamedia commented 9 months ago

I seem to have resolved the issue of requesting login after clicking the back button. You can go to my website (blankbro.site) to try it out. My solution is to annotate the following code ↓↓↓

// const open = window.XMLHttpRequest.prototype.open;
// window.XMLHttpRequest.prototype.open = function() {
//   arguments[1] = arguments[1].replace('${MY_DOMAIN}', 'www.notion.so');
//   return open.apply(this, [].slice.call(arguments));
// };

good luck 🎉

Jepretan Layar 2024-02-14 pukul 23 05 16 I have try like this, but still not working.

colinroper commented 3 months ago

Has anyone had any luck with this? I haven't figured out how to prevent the Notion login on using the back button.

I'm using https://github.com/velsa/notehost, so the login just flashes for a moment and then correctly redirects, but this behavior isn't ideal.

knownissuewontfix commented 3 months ago

I tried @eeshabarua 's fix and @blankbro 's fix and the dark/light fix. None of them worked for me. I found a new fix:

replace this line history.replaceState(history.state, 'bypass', '/' + page); to window.location.href = '/' + page; return;

(also mentioned at https://github.com/stephenou/fruitionsite/issues/264#issuecomment-2282834690)

also cc @DudeThatsErin I saw that your appseeker site is still has the issue, do you want to give it a try?

colinroper commented 3 months ago

@knownissuewontfix - that worked for me.

@DudeThatsErin: I'm using notehost and I edited index.cjs to match this suggestion. I'm not very good with Github but I can submit a PR for notehost if you can provide some guidance.

DudeThatsErin commented 2 months ago

@knownissuewontfix - that worked for me.

@DudeThatsErin: I'm using notehost and I edited index.cjs to match this suggestion. I'm not very good with Github but I can submit a PR for notehost if you can provide some guidance.

I'm not a maintainer so I can't approve it but this is how: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request