Skip to content

hub/analytics: make analytics cookie optional #8452

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

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 30 additions & 47 deletions src/packages/conat/core/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,53 +28,56 @@ cd packages/server
*/

import type { ConnectionStats, ServerInfo } from "./types";

import { delay } from "awaiting";
import { EventEmitter } from "events";
import { throttle } from "lodash";
import { Server } from "socket.io";

import { getClientIpAddress } from "@cocalc/util/get-client-ip-address";
import { getLogger } from "@cocalc/conat/client";
import { UsageMonitor } from "@cocalc/conat/monitor/usage";
import { type ConatSocketServer } from "@cocalc/conat/socket";
import {
isValidSubject,
isValidSubjectWithoutWildcards,
} from "@cocalc/conat/util";
import { Server } from "socket.io";
import { delay } from "awaiting";
import { once, until } from "@cocalc/util/async-utils";
import { is_array } from "@cocalc/util/misc";
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
import { Metrics } from "../types";
import {
ConatError,
connect,
Client,
type ClientOptions,
ConatError,
connect,
MAX_INTEREST_TIMEOUT,
STICKY_QUEUE_GROUP,
} from "./client";
import {
RESOURCE,
MAX_CONNECTIONS_PER_USER,
MAX_CONNECTIONS,
MAX_PAYLOAD,
MAX_SUBSCRIPTIONS_PER_CLIENT,
MAX_SUBSCRIPTIONS_PER_HUB,
} from "./constants";
import { Patterns } from "./patterns";
import { is_array } from "@cocalc/util/misc";
import { UsageMonitor } from "@cocalc/conat/monitor/usage";
import { once, until } from "@cocalc/util/async-utils";
import {
clusterLink,
type ClusterLink,
clusterStreams,
type ClusterStreams,
trimClusterStreams,
createClusterPersistServer,
Sticky,
Interest,
hashInterest,
hashSticky,
Interest,
Sticky,
trimClusterStreams,
} from "./cluster";
import { type ConatSocketServer } from "@cocalc/conat/socket";
import { throttle } from "lodash";
import { getLogger } from "@cocalc/conat/client";
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
import { type SysConatServer, sysApiSubject, sysApi } from "./sys";
import {
MAX_CONNECTIONS,
MAX_CONNECTIONS_PER_USER,
MAX_PAYLOAD,
MAX_SUBSCRIPTIONS_PER_CLIENT,
MAX_SUBSCRIPTIONS_PER_HUB,
RESOURCE,
} from "./constants";
import { Patterns } from "./patterns";
import { forkedConatServer } from "./start-server";
import { stickyChoice } from "./sticky";
import { EventEmitter } from "events";
import { Metrics } from "../types";
import { sysApi, sysApiSubject, type SysConatServer } from "./sys";

const logger = getLogger("conat:core:server");

Expand Down Expand Up @@ -1755,27 +1758,7 @@ export function randomChoice(v: Set<string>): string {

// See https://socket.io/how-to/get-the-ip-address-of-the-client
function getAddress(socket) {
const header = socket.handshake.headers["forwarded"];
if (header) {
for (const directive of header.split(",")[0].split(";")) {
if (directive.startsWith("for=")) {
return directive.substring(4);
}
}
}

let addr = socket.handshake.headers["x-forwarded-for"]?.split(",")?.[0];
if (addr) {
return addr;
}
for (const other of ["cf-connecting-ip", "fastly-client-ip"]) {
addr = socket.handshake.headers[other];
if (addr) {
return addr;
}
}

return socket.handshake.address;
return getClientIpAddress(socket.handshake) ?? socket.handshake.address;
}

export function updateInterest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const EmailAddressSetting = ({
return;
}
try {
// anonymouse users will get the "welcome" email
// anonymous users will get the "welcome" email
await webapp_client.account_client.send_verification_email(!is_anonymous);
} catch (error) {
const err_msg = `Problem sending welcome email: ${error}`;
Expand Down
24 changes: 13 additions & 11 deletions src/packages/frontend/user-tracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,33 @@
// client code doesn't have to import webapp_client everywhere, and we can
// completely change this if we want.

import { query, server_time } from "./frame-editors/generic/client";
import { analytics_cookie_name as analytics, uuid } from "@cocalc/util/misc";
import { redux } from "./app-framework";
import { redux } from "@cocalc/frontend/app-framework";
import {
query,
server_time,
} from "@cocalc/frontend/frame-editors/generic/client";
import { get_cookie } from "@cocalc/frontend/misc";
import { webapp_client } from "@cocalc/frontend/webapp-client";
import { uuid } from "@cocalc/util/misc";
import { version } from "@cocalc/util/smc-version";
import { get_cookie } from "./misc";
import { webapp_client } from "./webapp-client";

import { ANALYTICS_COOKIE_NAME } from "@cocalc/util/consts";

export async function log(eventName: string, payload: any): Promise<void> {
const central_log = {
id: uuid(),
event: `webapp-${eventName}`,
value: {
account_id: redux.getStore("account")?.get("account_id"),
analytics_cookie: get_cookie(analytics),
analytics_cookie: get_cookie(ANALYTICS_COOKIE_NAME),
cocalc_version: version,
...payload,
},
time: server_time(),
};

try {
await query({
query: {
central_log,
},
});
await query({ query: { central_log } });
} catch (err) {
console.warn("WARNING: Failed to write log event -- ", central_log);
}
Expand Down
15 changes: 9 additions & 6 deletions src/packages/hub/analytics-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@
* e.g. this filters the SSO auth pages, which are uninteresting referrals
*/

// variable PREFIX, NAME, DOMAIN and ID are injected in the hub's http server
declare var NAME, ID, DOMAIN, PREFIX, window, document;
// variable PREFIX, NAME, DOMAIN, ID, and ANALYTICS_ENABLED are injected in the hub's http server
declare var NAME, ID, DOMAIN, PREFIX, ANALYTICS_ENABLED, window, document;

// write cookie. it would be cool to set this via the http request itself,
// but for reasons I don't know it doesn't work across subdomains.
const maxage = 7 * 24 * 60 * 60; // 7 days
document.cookie = `${NAME}=${ID}; path=/; domain=${DOMAIN}; max-age=${maxage}`;
// write cookie only if analytics is enabled (for privacy in cookieless mode)
if (ANALYTICS_ENABLED) {
// it would be cool to set this via the http request itself,
// but for reasons I don't know it doesn't work across subdomains.
const maxage = 7 * 24 * 60 * 60; // 7 days
document.cookie = `${NAME}=${ID}; path=/; domain=${DOMAIN}; max-age=${maxage}`;
}

const { href, protocol, host, pathname } = window.location;

Expand Down
Loading