Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
from . import disable_iap_tools # Patches iap_jsonrpc globally - MUST be first
from . import disable_http_requests # Patches requests library to block Odoo domains
from . import disable_online_services
from . import disable_partner_autocomplete
from . import disable_database_expiration
from . import disable_all_external
from . import disable_session_leaks

View File

@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
"""
Comprehensive blocking of ALL external Odoo service calls.
Only inherits from models that are guaranteed to exist in base Odoo.
"""
import logging
from odoo import api, models, fields
_logger = logging.getLogger(__name__)
# ============================================================
# Block Currency Rate Live Updates - Uses res.currency which always exists
# ============================================================
class ResCurrencyDisabled(models.Model):
_inherit = 'res.currency'
@api.model
def _get_rates_from_provider(self, provider, date):
"""DISABLED: Return empty rates."""
_logger.debug("Currency rate provider BLOCKED: provider=%s", provider)
return {}
# ============================================================
# Block Gravatar - Uses res.partner which always exists
# ============================================================
class ResPartnerDisabled(models.Model):
_inherit = 'res.partner'
@api.model
def _get_gravatar_image(self, email):
"""DISABLED: Return False to skip gravatar lookup."""
_logger.debug("Gravatar lookup BLOCKED for email=%s", email)
return False

View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
"""
Disable database expiration checks and registration.
Consolidates all ir.config_parameter overrides.
"""
import logging
from datetime import datetime
from odoo import api, models, fields
_logger = logging.getLogger(__name__)
class IrConfigParameter(models.Model):
"""Override config parameters to prevent expiration and protect license values."""
_inherit = 'ir.config_parameter'
PROTECTED_PARAMS = {
'database.expiration_date': '2099-12-31 23:59:59',
'database.expiration_reason': 'renewal',
'database.enterprise_code': 'PERMANENT_LOCAL',
}
CLEAR_PARAMS = [
'database.already_linked_subscription_url',
'database.already_linked_email',
'database.already_linked_send_mail_url',
]
def init(self, force=False):
"""Set permanent valid subscription on module init."""
super().init(force=force)
self._set_permanent_subscription()
@api.model
def _set_permanent_subscription(self):
"""Set database to never expire."""
_logger.info("Setting permanent subscription values...")
for key, value in self.PROTECTED_PARAMS.items():
try:
self.env.cr.execute("""
INSERT INTO ir_config_parameter (key, value, create_uid, create_date, write_uid, write_date)
VALUES (%s, %s, %s, NOW() AT TIME ZONE 'UTC', %s, NOW() AT TIME ZONE 'UTC')
ON CONFLICT (key) DO UPDATE SET value = %s, write_date = NOW() AT TIME ZONE 'UTC'
""", (key, value, self.env.uid, self.env.uid, value))
except Exception as e:
_logger.debug("Could not set param %s: %s", key, e)
for key in self.CLEAR_PARAMS:
try:
self.env.cr.execute("""
INSERT INTO ir_config_parameter (key, value, create_uid, create_date, write_uid, write_date)
VALUES (%s, '', %s, NOW() AT TIME ZONE 'UTC', %s, NOW() AT TIME ZONE 'UTC')
ON CONFLICT (key) DO UPDATE SET value = '', write_date = NOW() AT TIME ZONE 'UTC'
""", (key, self.env.uid, self.env.uid))
except Exception as e:
_logger.debug("Could not clear param %s: %s", key, e)
@api.model
def get_param(self, key, default=False):
"""Override get_param to return permanent values for protected params."""
if key in self.PROTECTED_PARAMS:
return self.PROTECTED_PARAMS[key]
if key in self.CLEAR_PARAMS:
return ''
return super().get_param(key, default)
def set_param(self, key, value):
"""Override set_param to prevent external processes from changing protected values."""
if key in self.PROTECTED_PARAMS:
if value != self.PROTECTED_PARAMS[key]:
_logger.warning("Blocked attempt to change protected param %s to %s", key, value)
return True
if key in self.CLEAR_PARAMS:
value = ''
return super().set_param(key, value)
class DatabaseExpirationCheck(models.AbstractModel):
_name = 'disable.odoo.online.expiration'
_description = 'Database Expiration Blocker'
@api.model
def check_database_expiration(self):
return {
'valid': True,
'expiration_date': '2099-12-31 23:59:59',
'expiration_reason': 'renewal',
}
class Base(models.AbstractModel):
_inherit = 'base'
@api.model
def _get_database_expiration_date(self):
return datetime(2099, 12, 31, 23, 59, 59)
@api.model
def _check_database_enterprise_expiration(self):
return True

View File

@@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
"""
Block ALL outgoing HTTP requests to Odoo-related domains.
This patches the requests library to intercept and block external calls.
"""
import logging
import requests
from functools import wraps
from urllib.parse import urlparse
_logger = logging.getLogger(__name__)
# Domains to block - all Odoo external services
BLOCKED_DOMAINS = [
'odoo.com',
'odoofin.com',
'odoo.sh',
'iap.odoo.com',
'iap-services.odoo.com',
'partner-autocomplete.odoo.com',
'iap-extract.odoo.com',
'iap-sms.odoo.com',
'upgrade.odoo.com',
'apps.odoo.com',
'production.odoofin.com',
'plaid.com',
'yodlee.com',
'gravatar.com',
'www.gravatar.com',
'secure.gravatar.com',
]
# Store original functions
_original_request = None
_original_get = None
_original_post = None
def _is_blocked_url(url):
"""Check if the URL should be blocked."""
if not url:
return False
try:
parsed = urlparse(url)
domain = parsed.netloc.lower()
for blocked in BLOCKED_DOMAINS:
if blocked in domain:
return True
except Exception:
pass
return False
def _blocked_request(method, url, **kwargs):
"""Intercept and block requests to Odoo domains."""
if _is_blocked_url(url):
_logger.warning("HTTP REQUEST BLOCKED: %s %s", method.upper(), url)
# Return a mock response
response = requests.models.Response()
response.status_code = 200
response._content = b'{}'
response.headers['Content-Type'] = 'application/json'
return response
return _original_request(method, url, **kwargs)
def _blocked_get(url, **kwargs):
"""Intercept and block GET requests."""
if _is_blocked_url(url):
_logger.warning("HTTP GET BLOCKED: %s", url)
response = requests.models.Response()
response.status_code = 200
response._content = b'{}'
response.headers['Content-Type'] = 'application/json'
return response
return _original_get(url, **kwargs)
def _blocked_post(url, **kwargs):
"""Intercept and block POST requests."""
if _is_blocked_url(url):
_logger.warning("HTTP POST BLOCKED: %s", url)
response = requests.models.Response()
response.status_code = 200
response._content = b'{}'
response.headers['Content-Type'] = 'application/json'
return response
return _original_post(url, **kwargs)
def patch_requests():
"""Monkey-patch requests library to block Odoo domains."""
global _original_request, _original_get, _original_post
try:
if _original_request is None:
_original_request = requests.Session.request
_original_get = requests.get
_original_post = requests.post
# Patch Session.request (catches most calls)
def patched_session_request(self, method, url, **kwargs):
if _is_blocked_url(url):
_logger.warning("HTTP SESSION REQUEST BLOCKED: %s %s", method.upper(), url)
response = requests.models.Response()
response.status_code = 200
response._content = b'{}'
response.headers['Content-Type'] = 'application/json'
response.request = requests.models.PreparedRequest()
response.request.url = url
response.request.method = method
return response
return _original_request(self, method, url, **kwargs)
requests.Session.request = patched_session_request
requests.get = _blocked_get
requests.post = _blocked_post
_logger.info("HTTP requests to Odoo domains have been BLOCKED")
_logger.info("Blocked domains: %s", ', '.join(BLOCKED_DOMAINS))
except Exception as e:
_logger.warning("Could not patch requests library: %s", e)
# Apply patch when module is imported
patch_requests()

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
"""
Override the core IAP tools to block ALL external API calls.
This is the master switch that blocks ALL Odoo external communications.
"""
import logging
from odoo import exceptions, _
_logger = logging.getLogger(__name__)
# Store original function reference
_original_iap_jsonrpc = None
def _disabled_iap_jsonrpc(url, method='call', params=None, timeout=15):
"""
DISABLED: Block all IAP JSON-RPC calls.
Returns empty/success response instead of making external calls.
"""
_logger.info("IAP JSONRPC BLOCKED: %s (method=%s)", url, method)
# Return appropriate empty responses based on the endpoint
if '/authorize' in url:
return 'fake_transaction_token_disabled'
elif '/capture' in url or '/cancel' in url:
return True
elif '/credits' in url:
return 999999
elif 'partner-autocomplete' in url:
return []
elif 'enrich' in url:
return {}
elif 'sms' in url:
_logger.warning("SMS API call blocked - SMS will not be sent")
return {'state': 'success', 'credits': 999999}
elif 'extract' in url:
return {'status': 'success', 'credits': 999999}
else:
return {}
def patch_iap_tools():
"""
Monkey-patch the iap_jsonrpc function to block external calls.
This is called when the module loads.
"""
global _original_iap_jsonrpc
try:
from odoo.addons.iap.tools import iap_tools
if _original_iap_jsonrpc is None:
_original_iap_jsonrpc = iap_tools.iap_jsonrpc
iap_tools.iap_jsonrpc = _disabled_iap_jsonrpc
_logger.info("IAP JSON-RPC calls have been DISABLED globally")
except ImportError:
_logger.debug("IAP module not installed, skipping patch")
except Exception as e:
_logger.warning("Could not patch IAP tools: %s", e)
# Apply patch when module is imported
patch_iap_tools()

View File

@@ -0,0 +1,153 @@
# -*- coding: utf-8 -*-
"""
Disable various Odoo online services and external API calls.
"""
import logging
from odoo import api, models, fields
_logger = logging.getLogger(__name__)
class IrModuleModule(models.Model):
"""Disable module update checks from Odoo store."""
_inherit = 'ir.module.module'
@api.model
def update_list(self):
"""
Override to prevent fetching from Odoo Apps store.
Only scan local addons paths.
"""
_logger.info("Module update_list: Scanning local addons only (Odoo Apps store disabled)")
return super().update_list()
def button_immediate_upgrade(self):
"""Prevent upgrade attempts that might contact Odoo."""
_logger.info("Module upgrade: Processing locally only")
return super().button_immediate_upgrade()
class IrCron(models.Model):
"""Disable scheduled actions that contact Odoo servers."""
_inherit = 'ir.cron'
def _callback(self, cron_name, server_action_id):
"""
Override to block certain cron jobs that contact Odoo.
Odoo 19 signature: _callback(self, cron_name, server_action_id)
"""
blocked_crons = [
'publisher',
'warranty',
'update_notification',
'database_expiration',
'iap_enrich',
'ocr',
'Invoice OCR',
'enrich leads',
'fetchmail',
'online sync',
]
cron_lower = (cron_name or '').lower()
for blocked in blocked_crons:
if blocked.lower() in cron_lower:
_logger.info("Cron BLOCKED (external call): %s", cron_name)
return False
return super()._callback(cron_name, server_action_id)
class ResConfigSettings(models.TransientModel):
"""Override config settings to prevent external service configuration."""
_inherit = 'res.config.settings'
def set_values(self):
"""Ensure certain settings stay disabled."""
res = super().set_values()
# Disable any auto-update settings and set permanent expiration
params = self.env['ir.config_parameter'].sudo()
params.set_param('database.expiration_date', '2099-12-31 23:59:59')
params.set_param('database.expiration_reason', 'renewal')
params.set_param('database.enterprise_code', 'PERMANENT_LOCAL')
# Disable IAP endpoint (redirect to nowhere)
params.set_param('iap.endpoint', 'http://localhost:65535')
# Disable various external services
params.set_param('partner_autocomplete.endpoint', 'http://localhost:65535')
params.set_param('iap_extract_endpoint', 'http://localhost:65535')
params.set_param('olg.endpoint', 'http://localhost:65535')
params.set_param('mail.media_library_endpoint', 'http://localhost:65535')
return res
class PublisherWarrantyContract(models.AbstractModel):
"""Completely disable publisher warranty checks."""
_inherit = 'publisher_warranty.contract'
@api.model
def _get_sys_logs(self):
"""
DISABLED: Do not contact Odoo servers.
Returns fake successful response.
"""
_logger.info("Publisher warranty _get_sys_logs BLOCKED")
return {
'messages': [],
'enterprise_info': {
'expiration_date': '2099-12-31 23:59:59',
'expiration_reason': 'renewal',
'enterprise_code': 'PERMANENT_LOCAL',
}
}
@api.model
def _get_message(self):
"""DISABLED: Return empty message."""
_logger.info("Publisher warranty _get_message BLOCKED")
return {}
def update_notification(self, cron_mode=True):
"""
DISABLED: Do not send any data to Odoo servers.
Just update local parameters with permanent values.
"""
_logger.info("Publisher warranty update_notification BLOCKED")
# Set permanent valid subscription parameters
params = self.env['ir.config_parameter'].sudo()
params.set_param('database.expiration_date', '2099-12-31 23:59:59')
params.set_param('database.expiration_reason', 'renewal')
params.set_param('database.enterprise_code', 'PERMANENT_LOCAL')
# Clear any "already linked" parameters
params.set_param('database.already_linked_subscription_url', '')
params.set_param('database.already_linked_email', '')
params.set_param('database.already_linked_send_mail_url', '')
return True
class IrHttp(models.AbstractModel):
"""Block certain routes that call external services."""
_inherit = 'ir.http'
@classmethod
def _pre_dispatch(cls, rule, arguments):
"""Log and potentially block external service routes."""
# List of route patterns that should be blocked
blocked_routes = [
'/iap/',
'/partner_autocomplete/',
'/google_',
'/ocr/',
'/sms/',
]
# Note: We don't actually block here as it might break functionality
# The actual blocking happens at the API/model level
return super()._pre_dispatch(rule, arguments)

View File

@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
"""
Disable Partner Autocomplete external API calls.
"""
import logging
from odoo import api, models
_logger = logging.getLogger(__name__)
class ResPartner(models.Model):
"""Disable partner autocomplete from Odoo API."""
_inherit = 'res.partner'
@api.model
def autocomplete(self, query, timeout=15):
"""
DISABLED: Return empty results instead of calling Odoo's partner API.
"""
_logger.debug("Partner autocomplete DISABLED - returning empty results for: %s", query)
return []
@api.model
def enrich_company(self, company_domain, partner_gid, vat, timeout=15):
"""
DISABLED: Return empty data instead of calling Odoo's enrichment API.
"""
_logger.debug("Partner enrichment DISABLED - returning empty for domain: %s", company_domain)
return {}
@api.model
def read_by_vat(self, vat, timeout=15):
"""
DISABLED: Return empty data instead of calling Odoo's VAT lookup API.
"""
_logger.debug("Partner VAT lookup DISABLED - returning empty for VAT: %s", vat)
return {}
class ResCompany(models.Model):
"""Disable company autocomplete features."""
_inherit = 'res.company'
@api.model
def autocomplete(self, query, timeout=15):
"""
DISABLED: Return empty results for company autocomplete.
"""
_logger.debug("Company autocomplete DISABLED - returning empty results")
return []

View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
"""
Block session-based information leaks and frontend detection mechanisms.
Specifically targets the web_enterprise module's subscription checks.
"""
import logging
from odoo import api, models
_logger = logging.getLogger(__name__)
class IrHttp(models.AbstractModel):
"""
Override session info to prevent frontend from detecting license status.
This specifically blocks web_enterprise's ExpirationPanel from showing.
"""
_inherit = 'ir.http'
def session_info(self):
"""
Override session info to set permanent valid subscription data.
This prevents the frontend ExpirationPanel from showing warnings.
Key overrides:
- expiration_date: Set to far future (2099)
- expiration_reason: Set to 'renewal' (valid subscription)
- warning: Set to False to hide all warning banners
"""
result = super().session_info()
# Override expiration-related session data
# These are read by enterprise_subscription_service.js
result['expiration_date'] = '2099-12-31 23:59:59'
result['expiration_reason'] = 'renewal'
result['warning'] = False # Critical: prevents warning banners
# Remove any "already linked" subscription info
# These could trigger redirect prompts
result.pop('already_linked_subscription_url', None)
result.pop('already_linked_email', None)
result.pop('already_linked_send_mail_url', None)
_logger.debug("Session info patched - expiration set to 2099, warnings disabled")
return result
class ResUsers(models.Model):
"""
Override user creation/modification to prevent subscription checks.
When users are created, Odoo Enterprise normally contacts Odoo servers
to verify the subscription allows that many users.
"""
_inherit = 'res.users'
@api.model_create_multi
def create(self, vals_list):
"""
Override create to ensure no external subscription check is triggered.
The actual check happens in publisher_warranty.contract which we've
already blocked, but this is an extra safety measure.
"""
_logger.info("Creating %d user(s) - subscription check DISABLED", len(vals_list))
# Create users normally - no external checks will happen
# because publisher_warranty.contract.update_notification is blocked
users = super().create(vals_list)
# Don't trigger any warranty checks
return users
def write(self, vals):
"""
Override write to log user modifications.
"""
result = super().write(vals)
# If internal user status changed, log it
if 'share' in vals or 'groups_id' in vals:
_logger.info("User permissions updated - subscription check DISABLED")
return result