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

expose event.clientAddress #4289

Merged
merged 16 commits into from
Mar 14, 2022
Merged

expose event.clientAddress #4289

merged 16 commits into from
Mar 14, 2022

Conversation

Rich-Harris
Copy link
Member

@Rich-Harris Rich-Harris commented Mar 10, 2022

Supersedes #3993. This adds a new property to event, clientAddress, which adapters are expected to populate with the client IP address.

Will be very grateful for any contributions to this PR!

  • Populate clientAddress in dev and preview
  • Update adapters
    • Cloudflare/Cloudflare Workers
    • Netlify
    • Node (possibly using request-ip?) Needs to be behind an option of some sort, since we don't want to trust proxies on behalf of users
    • Vercel
    • Figure out which may have multiple values appended together (e.g. x-forwarded-for may) and whether we should split them
  • Update docs (happens automatically by updating types)
  • Warn on startup if getClientAddress is not provided changed my mind
  • Throw on accessing event.clientAddress if getClientAddress is not provided

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpx changeset and following the prompts. All changesets should be patch until SvelteKit 1.0

@changeset-bot
Copy link

changeset-bot bot commented Mar 10, 2022

🦋 Changeset detected

Latest commit: a548fa8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@sveltejs/adapter-cloudflare Patch
@sveltejs/adapter-cloudflare-workers Patch
@sveltejs/adapter-netlify Patch
@sveltejs/adapter-node Patch
@sveltejs/adapter-vercel Patch
@sveltejs/kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Rich-Harris
Copy link
Member Author

I just checked, and on Vercel x-forwarded-for only contains the client IP address so we're in the clear there. For Node we will want to do something like this

const [clientAddress] = headers.get('x-forwarded-for').split(',');

@Rich-Harris
Copy link
Member Author

Also, in 1fa6823 socket.remoteAddress is returned from getClientAddress if no header is specified or the header isn't present, so the proxy-less case works OOTB.

@evdama
Copy link

evdama commented Mar 14, 2022

  • I find that a good solution as node can be deployed in various ways and to many hosting platforms/providers, so there's no way to know what header to use here, thus the user has to provide this information via config 👍
  • For other adapters such as vercel, netlify etc. it's straight forward as it's known beforehand which header carries the IP address of the remote client connecting.

@TheRealThor
Copy link

Thank you @Rich-Harris, I think it perfect now.

@AlessioGr
Copy link

Would be awesome if someone could make an example as to how/where to use it. I'd like to have the IP address available in my svelte component - where exactly do I start? Where can I find the event.clientAddress field?

@ollyde
Copy link

ollyde commented Jul 3, 2022

Hey guys, this returns an invalid address on our production servers. Using node express (same server groups) returns a valid address so something is broken with clientAddress

@AlessioGr yeah they are bad at giving examples for people learning.

export async function post(data) {
    data.clientAddress
}

@ollyde
Copy link

ollyde commented Jul 3, 2022

#5348

@CAPTAIN320
Copy link

CAPTAIN320 commented Sep 20, 2023

Would be awesome if someone could make an example as to how/where to use it. I'd like to have the IP address available in my svelte component - where exactly do I start? Where can I find the event.clientAddress field?

@AlessioGr I made an example of how to get a user's ip address and subsequently the user's location using sveltekit.

Repo - https://github.com/CAPTAIN320/sveltekit-user-ip-location-example

@a4vg
Copy link

a4vg commented Oct 9, 2023

@CAPTAIN320 I see you're exporting a variable on hooks.server.ts. Since it runs on the server side, isn't the variable shared by all clients? The correct approach should be getting the ip in the load function of +page.server.ts and returning it so it's available on +page.svelte in the data variable.

@CAPTAIN320
Copy link

@CAPTAIN320 I see you're exporting a variable on hooks.server.ts. Since it runs on the server side, isn't the variable shared by all clients? The correct approach should be getting the ip in the load function of +page.server.ts and returning it so it's available on +page.svelte in the data variable.

@a4vg Getting the variable from the load function and having your app is deployed to a Paas such as Vercel, will result in the location of the vercel server being returned. Which was why I was getting US location for all my users.
Getting it from hooks.server.ts however, will prevent this behaviour and return the client ip instead.

From then on you can import it to any *.server.ts file.

@a4vg
Copy link

a4vg commented Oct 21, 2023

@CAPTAIN320 Maybe the solution works, but you should write the IP to event.locals (docs) and then access it on the load function instead of exporting a variable from hooks.server. The reason is because hooks.server runs on the server side and the variables that you put there will be shared by all users (correct me if I'm wrong, I'm just starting to use sveltekit), so it won't work as expected when multiple users try to access the application, one user could end up getting the IP from another user.


Now, for anyone else who can't still get the public IP address...

I was using Heroku FWIW, but I had the same issue where I couldn't get the real IP. getClientAddress was reporting a local IP.

I'm using the node-adapter and after reading this note on the docs:

If you need to read the left-most address instead (and don't care about spoofing) — for example, to offer a geolocation service, where it's more important for the IP address to be real than trusted, you can do so by inspecting the x-forwarded-for header within your app.

I added

// +page.server.ts
export const load: PageServerLoad = ({ request }) => {
    const ip = request.headers.get('x-forwarded-for') || '';

Another option is setting the env var ADDRESS_HEADER="X-Forwarded-For" and getClientAddress will start reporting the correct IP.

The node-adapter code shows exactly how getClientAddress works

req.connection?.remoteAddress ||
// @ts-expect-error
req.connection?.socket?.remoteAddress ||
req.socket?.remoteAddress ||
// @ts-expect-error
req.info?.remoteAddress

@Carlos-err406
Copy link

setting the ADDRESS_HEADER="X-Forwarded-For"
and using getClientAddress()
worked just fine for me

@mediocreaverage1
Copy link

mediocreaverage1 commented Dec 18, 2023

I'm a beginner., getclientaddress() is reporting 127.0.0.1 How do you do that? Where do you set the env var ADDRESS_HEADER?

@Carlos-err406
setting the ADDRESS_HEADER="X-Forwarded-For"
and using getClientAddress()
worked just fine for me

@Carlos-err406
Copy link

Carlos-err406 commented Dec 18, 2023

i did the test on a remote server
(if is worth anything im using adapter node)
i set up the app to log the output of the getClientAddress function so i could check on it and indeed accessing from my PC to the app logged the same IP i get from whatsmyip.com
tried from my phone as well (so a different IP was logged)

as for where to set the enviroment variable it was on my root .env as a regular enviroment variable, no further implications were required
(i ran the app with node -r dotenv/config build as the documentation says, if it helps)

@mediocreaverage1
Copy link

That was detailed and specific. Impressive and helpful. Thank you.

@leoj3n
Copy link
Contributor

leoj3n commented Feb 7, 2024

Here is a more complete example for anyone that it helps...

+page.server.js:

/** @type {import('./$types').PageServerLoad} */
export const load = async (event) => {
    let requestIp;
    
    try {
      requestIp = event.getClientAddress(); // IP from Client Request
      console.log('IP Address from Client Request: ', requestIp);
    } catch (error) {
      console.log('Error reading IP');
    }

    return { clientAddress: requestIp }
}

+page.svelte:

<script>
	import { onMount } from 'svelte';

	/** @type {import('./$types').PageData} */
	export let data;

	onMount(async () => {
		await import('@mux/mux-player');
	});
</script>

<mux-player
  playback-id="..."
  metadata-viewer-user-id="{data.clientAddress}"
></mux-player>

This worked deployed to Vercel with @sveltejs/adapter-vercel.

Didn't seem to need to add any environment config like ADDRESS_HEADER="X-Forwarded-For".

@travisdmathis
Copy link

anyone that's trying to figure out how to do this in 2024 from an API endpoint in Svelte 5, it's like this

export async function POST({ getClientAddress, request, url }) {
 let clientIp = getClientAddress();

Save yourself some time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.