Ctrl K
ComunidadGuías…

lib/pane-session-activation.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var provenance = require('./session-provenance');

// This opt-in protocol only describes an authenticated ordinary pane snapshot.
// It grants no action authority and is never a visible-render acknowledgement.
function begin(ctx, ws, msg) {
  if (!Object.prototype.hasOwnProperty.call(msg, 'paneActivation')) {
    ws._clayPaneActivation = null;
    return null;
  }
  var request = msg.paneActivation;
  var session = ctx.sm.sessions.get(msg.id);
  var userId = ws._clayUser && ws._clayUser.id || null;
  var worker = provenance.isWorker(session);
  var parentSession = worker && Array.from(ctx.sm.sessions.values()).find(function (parent) { return parent.sessionOriginId === session.sessionProvenance.parentSessionOriginId && !provenance.isWorker(parent); });
  var identity = session && {
    requestId: request && request.requestId,
    generation: request && request.generation,
    projectSlug: ctx.slug,
    viewerId: userId,
    ownerId: session.ownerId || null,
    sessionId: session.localId,
    sessionOriginId: session.sessionOriginId,
    role: worker ? 'worker' : 'driver',
    workerGeneration: worker ? session.sessionProvenance.generation : null,
    parentSessionOriginId: worker ? session.sessionProvenance.parentSessionOriginId : null,
    groupStamp: groupStamp(),
  };
  function groupStamp() {
    var group = ctx.splitStore && ctx.splitStore.groupForMember(msg.id);
    return group ? JSON.stringify({ id: group.id, members: group.members, pair: group.pair || null }) : null;
  }
  function allowed() {
    if (typeof ws._clayAuthCheck === 'function' && !ws._clayAuthCheck()) return false;
    var access = ctx.getProjectAccess ? ctx.getProjectAccess() : { visibility: 'public' };
    if (!ctx.usersModule.isMultiUser()) return !session.ownerId;
    return !!userId &&
      !!ctx.usersModule.findUserById(userId) &&
      ctx.usersModule.canAccessProject(userId, access) &&
      ctx.usersModule.canAccessSession(userId, session, access);
  }
  var valid = request && typeof request === 'object' &&
    typeof request.requestId === 'string' && /^[a-zA-Z0-9_-]{1,96}$/.test(request.requestId) &&
    Number.isSafeInteger(request.generation) && request.generation > (ws._clayPaneActivationGeneration || 0) &&
    ws._clayPane === true && !ws._clayContextual && !ctx.isMate && ws.readyState === 1 &&
    session && session.sessionOriginId && !session.isMate &&
    (session.runtimeMode || session.mode || 'gui') === 'gui' && !session.tuiSuspended &&
    request.projectSlug === identity.projectSlug && request.viewerId === identity.viewerId &&
    request.ownerId === identity.ownerId && request.sessionOriginId === identity.sessionOriginId &&
    request.role === identity.role && request.workerGeneration === identity.workerGeneration &&
    (!ctx.splitStore || request.groupStamp === identity.groupStamp && request.parentSessionOriginId === identity.parentSessionOriginId) &&
    (!worker || Number.isSafeInteger(identity.workerGeneration) && identity.workerGeneration > 0) && allowed();
  if (!valid) {
    // Do not disclose whether a foreign or removed session exists.
    ctx.sendTo(ws, { type: 'pane_activation_rejected', requestId: request && typeof request.requestId === 'string' ? request.requestId.slice(0, 96) : null });
    return false;
  }
  ws._clayPaneActivationGeneration = identity.generation;
  ws._clayPaneActivation = identity;
  function current() {
    return ws.readyState === 1 && ws._clayPane === true && !ws._clayContextual && !ctx.isMate && !session.isMate &&
      ws._clayPaneActivation === identity &&
      ctx.sm.sessions.get(msg.id) === session && session.sessionOriginId === identity.sessionOriginId &&
      (ws._clayUser && ws._clayUser.id || null) === userId &&
      (session.ownerId || null) === identity.ownerId &&
      (session.runtimeMode || session.mode || 'gui') === 'gui' && !session.tuiSuspended &&
      (provenance.isWorker(session) ? 'worker' : 'driver') === identity.role &&
      (provenance.isWorker(session) ? session.sessionProvenance.generation : null) === identity.workerGeneration &&
      groupStamp() === identity.groupStamp &&
      (!worker || parentSession && ctx.sm.sessions.get(parentSession.localId) === parentSession &&
        session.sessionProvenance.parentSessionOriginId === identity.parentSessionOriginId && parentSession.sessionOriginId === identity.parentSessionOriginId &&
        !provenance.isWorker(parentSession) && (parentSession.ownerId || null) === identity.ownerId) &&
      allowed();
  }
  function send(message) {
    if (current() && ws._clayActiveSession === session.localId) ctx.sendTo(ws, Object.assign({}, message, { paneActivation: identity }));
  }
  var historyItems = [], historyText = 0;
  // Only synchronous replay uses this bounded envelope. Each actual disclosure
  // rechecks live authorization; nothing is cached across a send or async work.
  send.history = function (message) {
    if (message.type === 'history_done') {
      flushHistory();
      send(message);
      return;
    }
    historyItems.push(message);
    historyText += typeof message.text === 'string' ? message.text.length : 0;
    if (historyItems.length >= 100 || historyText >= 65536) flushHistory();
  };
  function flushHistory() {
    if (!historyItems.length) return;
    var items = historyItems;
    historyItems = []; historyText = 0;
    send({ type: 'pane_history_batch', items: items });
  }
  if (current()) ctx.sendTo(ws, { type: 'pane_activation_started', paneActivation: identity });
  ws._clayPaneActivationValid = function () { return current() && ws._clayActiveSession === identity.sessionId; };
  return {
    validate: function () {
      if (current()) return true;
      ctx.sendTo(ws, { type: 'pane_activation_rejected', requestId: identity.requestId });
      ws._clayPaneActivation = null;
      return false;
    },
    send: send,
    finish: function () {
      // Includes history listeners, status, permissions and context sources.
      // Consumers still need to observe their own DOM/composer readiness.
      if (ws._clayActiveSession === session.localId) send({ type: 'pane_activation_snapshot_done' });
    },
  };
}

module.exports = { begin: begin };