Commit 91281ef5 authored by Grant's avatar Grant
Browse files

Track IP addresses for alternate account discovery

parent 18449235
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ Table User {
  FactionMember FactionMember [not null]
  Ban Ban
  AuditLog AuditLog [not null]
  IPAddress IPAddress [not null]
}

Table Instance {
@@ -32,6 +33,18 @@ Table Instance {
  Ban Ban
}

Table IPAddress {
  ip String [not null]
  userSub String [not null]
  lastUsedAt DateTime [not null]
  createdAt DateTime [default: `now()`, not null]
  user User [not null]

  indexes {
    (ip, userSub) [pk]
  }
}

Table PaletteColor {
  id Int [pk, increment]
  name String [not null]
@@ -145,6 +158,8 @@ Enum AuditLogAction {
  USER_UNADMIN
}

Ref: IPAddress.userSub > User.sub

Ref: Pixel.userId > User.sub

Ref: FactionMember.sub > User.sub
+12 −0
Original line number Diff line number Diff line
-- CreateTable
CREATE TABLE "IPAddress" (
    "ip" TEXT NOT NULL,
    "userSub" TEXT NOT NULL,
    "lastUsedAt" TIMESTAMP(3) NOT NULL,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "IPAddress_pkey" PRIMARY KEY ("ip","userSub")
);

-- AddForeignKey
ALTER TABLE "IPAddress" ADD CONSTRAINT "IPAddress_userSub_fkey" FOREIGN KEY ("userSub") REFERENCES "User"("sub") ON DELETE RESTRICT ON UPDATE CASCADE;
+13 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ model User {
  FactionMember FactionMember[]
  Ban           Ban?
  AuditLog      AuditLog[]
  IPAddress     IPAddress[]
}

model Instance {
@@ -47,6 +48,18 @@ model Instance {
  Ban        Ban?
}

model IPAddress {
  ip      String
  userSub String

  lastUsedAt DateTime
  createdAt  DateTime @default(now())

  user User @relation(fields: [userSub], references: [sub])

  @@id([ip, userSub])
}

model PaletteColor {
  id   Int    @id @default(autoincrement())
  name String
+55 −0
Original line number Diff line number Diff line
@@ -417,6 +417,61 @@ app.put("/canvas/fill", async (req, res) => {
  res.json({ success: true, auditLog });
});

/**
 * Get ip address info
 *
 * @query address IP address
 */
app.get("/ip", async (req, res) => {
  if (typeof req.query.address !== "string") {
    return res.status(400).json({ success: false, error: "missing ?address=" });
  }

  const ip: string = req.query.address;

  const results = await prisma.iPAddress.findMany({
    select: {
      userSub: true,
      createdAt: true,
      lastUsedAt: true,
    },
    where: {
      ip,
    },
  });

  res.json({ success: true, results });
});

/**
 * Get all of a user's IP addresses
 *
 * @param :sub User ID
 */
app.get("/user/:sub/ips", async (req, res) => {
  let user: User;

  try {
    user = await User.fromSub(req.params.sub);
  } catch (e) {
    if (e instanceof UserNotFound) {
      res.status(404).json({ success: false, error: "User not found" });
    } else {
      Logger.error(`/user/${req.params.sub}/ips Error ` + (e as any)?.message);
      res.status(500).json({ success: false, error: "Internal error" });
    }
    return;
  }

  const ips = await prisma.iPAddress.findMany({
    where: {
      userSub: user.sub,
    },
  });

  res.json({ success: true, ips });
});

/**
 * Create or ban a user
 *
+11 −0
Original line number Diff line number Diff line
@@ -164,6 +164,17 @@ export class SocketServer {
    );

    user?.sockets.add(socket);

    let ip = socket.handshake.address;
    if (process.env.NODE_ENV === "production") {
      if (typeof socket.handshake.headers["x-forwarded-for"] === "string") {
        ip = socket.handshake.headers["x-forwarded-for"];
      } else {
        ip = socket.handshake.headers["x-forwarded-for"]?.[0] || ip;
      }
    }
    user?.trackIP(ip);

    Logger.debug("handleConnection " + user?.sockets.size);
    socket.emit("clearCanvasChunks");

Loading