upstream: integrar Oasis 1.3.1

Base del merge a tres bandas: git 0.9.5 de epsylon, esta rama y el src de la
APK oficial 1.3.1 (la variante movil: OASIS_MOBILE, regex sin \p{}, audio y
video de Android). Corre en el mismo nodejs-mobile 18.20.4 que ya usabamos.

Se conserva de la rama: Karvan, identidades y multicuenta, topbar y barra
inferior, borrado de EXIF sin sharp, filtro hot del foro, RTC sin STUN y los
modulos apagados en movil (wallet, banking, torrents).

Se toma de upstream lo que ya hace de serie: respuesta citada en chats, ssb-lan
en movil, configuracion en ~/.ssb/oasis (sobrevive a reinstalar el backend).
El asistente de bienvenida deja elegir workflow tambien en movil.
This commit is contained in:
oasis-bot 2026-10-18 02:52:17 +02:00
parent 8d838dd8b1
commit c332afd6ea
265 changed files with 80970 additions and 29167 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

View file

@ -261,7 +261,7 @@ h3 { font-size: 1em !important; }
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
justify-content: center !important;
justify-content: flex-start !important;
align-items: center !important;
width: 100% !important;
max-width: 100% !important;
@ -288,8 +288,8 @@ h3 { font-size: 1em !important; }
}
.inhabitant-action .filter-btn {
min-height: 0 !important;
padding: 7px 12px !important;
font-size: 13px !important;
padding: 2px 9px !important;
font-size: .75em !important;
white-space: nowrap !important;
}
.profile-sensors-box {
@ -315,8 +315,8 @@ h3 { font-size: 1em !important; }
.activity-filter-col .filter-btn,
.activity-sub-filter .filter-btn {
min-height: 0 !important;
padding: 7px 12px !important;
font-size: 13px !important;
padding: 2px 9px !important;
font-size: .75em !important;
white-space: nowrap !important;
}
@ -450,10 +450,6 @@ h3 { font-size: 1em !important; }
grid-template-columns: repeat(2, 1fr) !important;
}
.tribe-media-grid {
grid-template-columns: repeat(2, 1fr) !important;
}
.tribe-overview-grid {
grid-template-columns: 1fr !important;
}
@ -466,24 +462,11 @@ h3 { font-size: 1em !important; }
height: 180px !important;
}
.tribe-votation-option {
flex-direction: column !important;
align-items: flex-start !important;
}
.tribe-content-header {
flex-direction: column !important;
gap: 8px !important;
}
.tribe-content-filters {
flex-wrap: wrap !important;
}
.tribe-media-filters {
flex-wrap: wrap !important;
}
.forum-card {
flex-direction: column !important;
}
@ -626,6 +609,7 @@ a.filter-btn,
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
flex: 0 0 auto !important;
height: 42px !important;
font-size: 16px !important;
box-sizing: border-box !important;
@ -672,7 +656,7 @@ a.filter-btn,
padding: 9px 16px !important;
}
.filters .ui-toolbar--filters {
justify-content: center !important;
justify-content: flex-start !important;
align-items: center !important;
gap: 6px !important;
}
@ -728,6 +712,15 @@ a.filter-btn,
max-width: 100% !important;
overflow-wrap: anywhere !important;
}
.card-field .card-value.user-link,
.card-field .card-value .user-link {
display: inline-block !important;
vertical-align: bottom !important;
max-width: 100% !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
.market-grid,
.shop-products-grid,
@ -817,14 +810,14 @@ a.filter-btn,
margin-left: 0 !important;
}
.oasis-id-copy {
input.oasis-id-copy[readonly] {
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
font-family: monospace !important;
font-size: 12px !important;
font-size: clamp(8px, 2.5vw, 12px) !important;
text-align: center !important;
padding: 8px !important;
padding: 8px 6px !important;
border: 1px solid #FFA500 !important;
border-radius: 8px !important;
background: rgba(255, 165, 0, 0.08) !important;
@ -849,6 +842,7 @@ a.create-button {
.peers-list .block-info-table,
.peers-technical-block .block-info-table,
.parliament-rows-table,
.gov-overview {
display: block !important;
width: 100% !important;
@ -859,17 +853,20 @@ a.create-button {
}
.peers-list .block-info-table tbody,
.peers-technical-block .block-info-table tbody,
.parliament-rows-table tbody,
.gov-overview tbody {
display: block !important;
width: 100% !important;
}
.gov-overview thead { display: none !important; }
.gov-overview thead,
.parliament-rows-table thead { display: none !important; }
.peers-list .block-info-table tr:first-child,
.peers-technical-block .block-info-table tr:first-child {
display: none !important;
}
.peers-list .block-info-table tr,
.peers-technical-block .block-info-table tr,
.parliament-rows-table tbody tr,
.gov-overview tbody tr {
display: block !important;
width: 100% !important;
@ -882,6 +879,7 @@ a.create-button {
}
.peers-list .block-info-table td,
.peers-technical-block .block-info-table td,
.parliament-rows-table tbody td,
.gov-overview tbody td {
display: flex !important;
justify-content: space-between !important;
@ -897,6 +895,7 @@ a.create-button {
}
.peers-list .block-info-table td::before,
.peers-technical-block .block-info-table td::before,
.parliament-rows-table tbody td::before,
.gov-overview tbody td::before {
content: attr(data-label);
flex: 0 0 auto !important;
@ -913,6 +912,121 @@ a.create-button {
.peers-technical-block .block-info-table td[data-label=""]::before { content: none !important; }
.peers-list .block-info-table td .peer-key,
.peers-technical-block .block-info-table td .peer-key { text-align: right !important; }
.phone-history td.phone-dir,
.phone-contact .phone-dir,
.phone-dir {
display: none !important;
}
.phone-contact {
gap: 6px !important;
padding: 8px !important;
}
.phone-contact .user-link {
flex: 1 1 100% !important;
min-width: 0 !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
.phone-contact .date-link {
flex: 0 1 auto !important;
font-size: 12px !important;
}
.phone-history,
.phone-history tbody {
display: block !important;
width: 100% !important;
}
.phone-history tr:first-child {
display: none !important;
}
.phone-history tr {
display: block !important;
width: 100% !important;
box-sizing: border-box !important;
border: 1px solid #444 !important;
border-radius: 10px !important;
margin: 0 0 8px 0 !important;
padding: 4px 10px !important;
}
.phone-history td {
display: flex !important;
justify-content: space-between !important;
align-items: baseline !important;
gap: 10px !important;
width: 100% !important;
border: 0 !important;
padding: 3px 0 !important;
font-size: 12px !important;
text-align: right !important;
}
.phone-history td::before {
content: attr(data-label);
flex: 0 0 auto !important;
font-weight: 700 !important;
text-transform: uppercase;
font-size: 10px !important;
letter-spacing: .03em;
opacity: .7 !important;
text-align: left !important;
white-space: nowrap !important;
}
.phone-history td.phone-row-actions {
justify-content: flex-end !important;
padding: 0 !important;
margin-top: -6px !important;
}
.phone-history .phone-row-delete .btn-singleview,
.phone-latest-row .phone-row-delete .btn-singleview {
width: 32px !important;
height: 32px !important;
min-width: 0 !important;
min-height: 0 !important;
line-height: 1 !important;
padding: 0 !important;
font-size: 14px !important;
}
.phone-history td.phone-row-actions::before {
content: none !important;
}
.phone-latest-row .phone-row-delete {
margin-left: auto !important;
}
.phone-history td .user-link {
min-width: 0 !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
.peers-list .block-info-table td .ubi-tick-ok,
.peers-list .block-info-table td .peer-tor-no,
.peers-technical-block .block-info-table td .ubi-tick-ok,
.peers-technical-block .block-info-table td .peer-tor-no {
padding: 0 !important;
line-height: 1.2 !important;
}
.conn-actions,
.peers-conn-actions {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
gap: 8px !important;
width: 100% !important;
}
.conn-actions form,
.peers-conn-actions form {
flex: 1 1 45% !important;
min-width: 130px !important;
max-width: 100% !important;
margin: 0 !important;
display: block !important;
}
.conn-actions form button,
.peers-conn-actions form button {
width: 100% !important;
min-width: 0 !important;
}
.relationship-status .relationship-actions { flex-direction: column !important; align-items: stretch !important; gap: 8px !important; }
.relationship-status .relationship-actions form,
@ -921,10 +1035,21 @@ a.create-button {
.profile-sensors-box { align-items: center !important; text-align: center !important; }
.profile-sensors-box > * { margin-left: auto !important; margin-right: auto !important; justify-content: center !important; }
.tribe-feed .refeed-column,
.tribe-feed-full .refeed-column { align-self: center !important; align-items: center !important; justify-content: center !important; }
.tribe-feed .card-footer,
.tribe-feed-full .card-footer { display: flex !important; flex-direction: column !important; align-items: center !important; text-align: center !important; gap: 2px !important; }
.profile-layout,
.profile-layout .tribe-side,
.profile-layout .tribe-main {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
.profile-side-description,
.profile-side-description p,
.trending-card .card-section,
.feed-text {
word-break: normal !important;
overflow-wrap: break-word !important;
}
.invite-qr-card { display: flex !important; justify-content: center !important; border: none !important; background: transparent !important; padding: 0 !important; box-shadow: none !important; margin: 0 auto !important; }
.invite-qr-img { display: block; margin: 0 auto; }
@ -942,3 +1067,445 @@ a.create-button {
.chat-messages-list { padding: 0 !important; }
.chat-message { max-width: 92% !important; }
.chat-message.chat-poll { max-width: 97% !important; }
.feed-workspace {
display: block !important;
}
.feed-side {
display: none !important;
}
.tribe-info-table,
.tribe-info-table tbody,
.tribe-info-table tr,
.tribe-info-table td {
display: block !important;
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
text-align: left !important;
overflow: visible !important;
}
.tribe-info-table td .user-link {
display: inline-block !important;
max-width: 100% !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
.school-lesson-summary {
flex-wrap: wrap !important;
}
.school-lesson-summary-title {
flex: 1 1 100% !important;
min-width: 0 !important;
white-space: normal !important;
overflow-wrap: anywhere !important;
}
.school-lesson-summary-meta {
flex: 1 1 100% !important;
white-space: normal !important;
}
.feed-votes-summary {
flex-wrap: wrap !important;
max-width: 100% !important;
min-width: 0 !important;
}
.feed-votes-summary .vote-category {
white-space: nowrap !important;
flex: 0 0 auto !important;
}
.tribe-open-invite-code {
font-size: .85em !important;
}
.school-progress-row {
flex-direction: column !important;
align-items: flex-start !important;
gap: 6px !important;
}
.school-progress-issue {
width: 100% !important;
}
.school-progress-issue input[type="text"] {
max-width: 100% !important;
flex: 1 1 100% !important;
}
.subscription-box-block {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 8px !important;
}
.subscription-box-block .subscription-form { margin: 0 !important; }
.profile-module-section,
.profile-module-section .trending-card,
.profile-module-section .card-body,
.profile-module-section .card-section {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
box-sizing: border-box !important;
}
.card-section-action {
display: flex !important;
justify-content: center !important;
width: 100% !important;
}
.card-section-action .keep-reading-link {
text-align: center !important;
}
.card-field.image-container,.card-field.video-container,.card-field.audio-container { justify-content: center !important; }
.card-field.media-left { justify-content: flex-start !important; }
.card-footer .date-link,
.card-footer .user-link { padding: 0 10px !important; font-size: 12px !important; }
.card-meta-row .opinions-summary,
.card-meta-row .comments-summary-link { padding: 0 10px !important; font-size: 12px !important; }
.parliament-rows-table tbody td[data-label=""] { justify-content: center !important; }
.parliament-rows-table tbody td[data-label=""]::before { content: none !important; }
.parliament-rows-table tbody td .parliament-avatar-cell {
display: flex !important;
align-items: center !important;
gap: 8px !important;
justify-content: flex-end !important;
}
.parliament-rows-table tbody td .parliament-leader-avatar { width: 32px !important; height: 32px !important; }
.parliament-rows-table tbody td .parliament-method-img { max-height: 28px !important; width: auto !important; }
.parliament-rows-table tbody td form { margin: 0 !important; }
.hemi-legend {
flex-direction: column !important;
align-items: flex-start !important;
gap: 6px !important;
justify-content: flex-start !important;
}
.hemi-legend-item {
width: 100% !important;
flex-wrap: nowrap !important;
justify-content: flex-start !important;
}
.hemi-legend-count { margin-left: auto !important; }
.hemi-modes { flex-wrap: wrap !important; }
.room-item .mailing-archive-head{flex-wrap:wrap}
.oasis-nav-side-toggle {
position: absolute !important;
width: 1px !important;
height: 1px !important;
opacity: 0 !important;
pointer-events: none !important;
}
.oasis-nav-side-toggle ~ .header {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 8px 6px !important;
padding: 8px 8px 4px !important;
min-height: 60px !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
z-index: 900 !important;
box-sizing: border-box !important;
}
.oasis-nav-side-toggle ~ .header + * ,
.oasis-nav-side-toggle ~ .header ~ .update-banner:first-of-type {
margin-top: 0 !important;
}
body:has(.oasis-nav-side-toggle) {
padding-top: 64px !important;
}
body:has(:is(input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]), textarea, select):focus) .oasis-nav-side-toggle ~ .header {
position: absolute !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left,
.oasis-nav-side-toggle ~ .header .top-bar-right,
.oasis-nav-side-toggle ~ .header .top-bar-mid {
display: contents !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left a.logo-icon {
order: 1 !important;
flex: 0 0 auto !important;
margin: 0 !important;
padding: 0 !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left a.logo-icon img.logo-icon {
width: 44px !important;
height: 44px !important;
margin: 0 !important;
}
.oasis-nav-side-toggle ~ .header .oasis-mobile-menus {
order: 2 !important;
display: flex !important;
flex: 1 1 auto !important;
flex-wrap: nowrap !important;
justify-content: flex-end !important;
align-items: center !important;
gap: 5px !important;
margin: 0 !important;
padding: 0 !important;
}
.oasis-nav-side-toggle ~ .header .oasis-menu-slot {
display: inline-flex !important;
}
.oasis-nav-side-toggle ~ .header .oasis-menu-btn {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
gap: 4px !important;
min-height: 44px !important;
padding: 6px 9px !important;
white-space: nowrap !important;
cursor: pointer !important;
}
.oasis-nav-side-toggle ~ .header .oasis-menu-slot .oasis-menu-close {
display: none !important;
}
#nav-left-toggle:checked ~ .header .oasis-menu-slot-left .oasis-menu-open,
#nav-right-toggle:checked ~ .header .oasis-menu-slot-right .oasis-menu-open {
display: none !important;
}
#nav-left-toggle:checked ~ .header .oasis-menu-slot-left .oasis-menu-close,
#nav-right-toggle:checked ~ .header .oasis-menu-slot-right .oasis-menu-close {
display: inline-flex !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav {
order: 3 !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-right nav {
order: 4 !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav,
.oasis-nav-side-toggle ~ .header .top-bar-right nav {
flex: 1 1 calc(50% - 4px) !important;
width: auto !important;
min-width: 0 !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav ul,
.oasis-nav-side-toggle ~ .header .top-bar-right nav ul {
display: grid !important;
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
gap: 4px !important;
list-style: none !important;
padding: 0 !important;
margin: 0 !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav ul li,
.oasis-nav-side-toggle ~ .header .top-bar-right nav ul li {
margin: 0 !important;
min-width: 0 !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav ul li a,
.oasis-nav-side-toggle ~ .header .top-bar-right nav ul li a {
position: relative !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
min-height: 50px !important;
padding: 0 !important;
font-size: 0 !important;
text-decoration: none !important;
box-sizing: border-box !important;
}
.oasis-nav-side-toggle ~ .header nav ul li a .nav-text {
display: none !important;
}
.oasis-nav-side-toggle ~ .header nav ul li a .emoji {
font-size: 1.6rem !important;
line-height: 1 !important;
margin: 0 !important;
}
.oasis-nav-side-toggle ~ .header nav ul li a .inbox-badge {
position: absolute !important;
top: 3px !important;
right: 3px !important;
margin: 0 !important;
font-size: 0.66rem !important;
}
.oasis-nav-side-toggle ~ .main-content {
display: flex !important;
flex-direction: column !important;
}
.oasis-nav-side-toggle ~ .main-content .main-column {
order: 0 !important;
}
.oasis-nav-side-toggle ~ .main-content .sidebar-left,
.oasis-nav-side-toggle ~ .main-content .sidebar-right {
display: none !important;
}
#nav-left-toggle:checked ~ .main-content .sidebar-left,
#nav-right-toggle:checked ~ .main-content .sidebar-right {
display: block !important;
order: -1 !important;
width: 100% !important;
max-width: 100% !important;
padding: 0 4px !important;
margin: 0 0 8px 0 !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-header {
margin: 0 0 6px 0 !important;
padding: 12px !important;
}
.oasis-nav-side-toggle ~ .main-content .sidebar-left .oasis-nav-list,
.oasis-nav-side-toggle ~ .main-content .sidebar-right .oasis-nav-list {
display: grid !important;
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
gap: 8px !important;
margin: 0 !important;
padding: 0 !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-list li {
margin: 0 !important;
padding: 0 !important;
min-width: 0 !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-list li a {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 74px !important;
height: 100% !important;
padding: 8px 4px !important;
margin: 0 !important;
text-align: center !important;
font-size: 0.72rem !important;
opacity: 1 !important;
box-sizing: border-box !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-list li a .emoji {
width: auto !important;
font-size: 1.5rem !important;
line-height: 1 !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-list li a .nav-text {
line-height: 1.15 !important;
overflow-wrap: anywhere !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav,
.oasis-nav-side-toggle ~ .header .top-bar-right nav {
position: fixed !important;
bottom: 0 !important;
height: 66px !important;
width: 50% !important;
flex: none !important;
z-index: 900 !important;
margin: 0 !important;
box-sizing: border-box !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav {
left: 0 !important;
right: auto !important;
padding: 6px 2px 6px 6px !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-right nav {
right: 0 !important;
left: auto !important;
padding: 6px 6px 6px 2px !important;
}
.oasis-nav-side-toggle ~ .oasis-footer {
padding-bottom: 84px !important;
}
body:has(:is(input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]), textarea, select):focus) .oasis-nav-side-toggle ~ .header .top-bar-left nav,
body:has(:is(input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]), textarea, select):focus) .oasis-nav-side-toggle ~ .header .top-bar-right nav {
display: none !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-left nav {
width: calc(300% / 7) !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-right nav {
width: calc(400% / 7) !important;
}
.oasis-nav-side-toggle ~ .header .top-bar-right nav ul {
grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
}
.oasis-nav-side-toggle ~ .main-content .sidebar-left nav > ul,
.oasis-nav-side-toggle ~ .main-content .sidebar-right nav > ul {
display: grid !important;
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
grid-auto-flow: row dense !important;
gap: 8px !important;
list-style: none !important;
padding: 0 !important;
margin: 0 !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-group {
display: contents !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-group > .oasis-nav-header {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
gap: 6px !important;
min-height: 74px !important;
margin: 0 !important;
padding: 8px 4px !important;
text-align: center !important;
font-size: 0.68rem !important;
box-sizing: border-box !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-group > .oasis-nav-header .emoji {
width: auto !important;
font-size: 1.5rem !important;
line-height: 1 !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-group > .oasis-nav-header .nav-text {
flex: 0 0 auto !important;
line-height: 1.15 !important;
overflow-wrap: anywhere !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-group > .oasis-nav-header .oasis-nav-arrow {
display: none !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-group > .oasis-nav-list {
grid-column: 1 / -1 !important;
max-height: none !important;
overflow: visible !important;
}
.oasis-nav-side-toggle ~ .main-content .oasis-nav-toggle:not(:checked) + .oasis-nav-header + .oasis-nav-list {
display: none !important;
}
.oasis-nav-side-toggle ~ .header .oasis-phone-state {
order: 1 !important;
flex: 1 1 0 !important;
display: flex !important;
justify-content: center !important;
align-items: center !important;
align-self: center !important;
margin: 0 !important;
padding: 0 !important;
min-width: 0 !important;
}
.oasis-nav-side-toggle ~ .header:has(.oasis-phone-state) .oasis-mobile-menus {
flex: 0 1 auto !important;
}
.oasis-nav-side-toggle ~ .header .oasis-phone-state-btn {
appearance: none !important;
-webkit-appearance: none !important;
font: inherit !important;
display: inline-flex !important;
align-items: center !important;
gap: 3px !important;
min-height: 0 !important;
justify-content: center !important;
width: 38px !important;
height: 38px !important;
padding: 0 !important;
font-size: 8.5px !important;
line-height: 1.2 !important;
white-space: nowrap !important;
border-radius: 999px !important;
cursor: pointer !important;
}
.oasis-nav-side-toggle ~ .header .oasis-phone-state-btn .pm-exposition-icon {
font-size: 22px !important;
line-height: 1 !important;
margin: 0 !important;
}

File diff suppressed because it is too large Load diff

View file

@ -224,32 +224,23 @@ footer a:hover {
background: none;
}
.card-tags a.tag-link {
color: #181818;
background: #D94F4F;
}
.card-tags a.tag-link:hover {
background: #D94F4F;
color: #111;
cursor: pointer;
}
a.user-link {
a.user-link, button.user-link {
background-color: #FFD600;
color: #FFFFFF;
border-color: #FFD600;
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
}
a.user-link:hover {
a.user-link:hover, button.user-link:hover {
background-color: #FFD600;
border-color: #FFD600;
color: #FFFFFF;
cursor: pointer;
}
a.user-link:focus {
a.user-link:focus, button.user-link:focus {
background-color: #9A2F2F;
border-color: #9A2F2F;
color: #FFFFFF;
@ -302,7 +293,7 @@ a.user-link:focus {
.stats-kpi-value { color: #007BFF !important; }
.carbon-bar-note, .carbon-bar-formula { color: #007BFF !important; }
.graphos-node-label { fill: #2C2C2C !important; }
.graphos-node-label-me { fill: #cc7700 !important; }
.graphos-node-label-me { fill: #1f6391 !important; }
.data-best-label { color: #cc7700 !important; }
.data-best-card { background: #FFF3E0 !important; border: 1px solid rgba(204, 119, 0, .4) !important; }
.graphos-legend { color: #2C2C2C !important; }
@ -327,6 +318,8 @@ a.user-link:focus {
.btn-singleview:hover { background: #E0E0E0 !important; color: #FF8F00 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #FF6F00 !important; color: #FFFFFF !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #FF8F00 !important; color: #FFFFFF !important; }
.content-actions .btn-singleview.btn-content { border: 1px solid #FF6F00 !important; }
.content-actions .btn-singleview.btn-content:hover { background: rgba(255, 111, 0, .18) !important; border-color: #FF6F00 !important; }
.btn-back { background: #FF6F00 !important; color: #FFFFFF !important; }
.btn-back:hover { background: #FF8F00 !important; color: #FFFFFF !important; }
.block-info-table td, .pm-info-table td { border-color: #E0E0E0 !important; }
@ -383,3 +376,48 @@ a.user-link:focus {
.karvan-msg-self { background-color: #FFEFC2 !important; border-color: #D9A400 !important; }
.karvan-msg .km-from { color: #8A6D00 !important; }
.karvan-msg .km-text { color: #2C2C2C !important; }
.map-viewer, .map-stage div, .map-hero, .map-toolbar, .map-toolbar div, .map-place-results, .map-markers-list, .map-markers-list div, .map-detail-grid, .map-card-thumb .map-viewer { background: transparent !important; border: 0 !important; }
.map-pick-cell, .map-pick-cell:hover { border: 0 !important; padding: 0 !important; border-radius: 0 !important; box-shadow: none !important; }
.map-pick-cell { background: transparent !important; }
.map-pick-cell:hover { background: rgba(255, 111, 0, 0.18) !important; }
.map-ctrl, .map-place-result { padding: 0 !important; border-radius: 6px !important; box-shadow: none !important; }
.map-place-result { padding: 4px 10px !important; border-radius: 14px !important; }
.map-stage { background: #cfe0ec !important; border: 1px solid #E0E0E0 !important; }
.map-marker-row { border-bottom: 1px solid #E0E0E0 !important; }
.map-label-country { fill: #4a4a4a; stroke: #ffffff; }
.map-place-dot { fill: #333333; stroke: #ffffff; }
.map-place-capital { fill: #E65100; }
.map-place-label { fill: #222222; stroke: #ffffff; }
.map-pin-label-bg { fill: rgba(255, 255, 255, 0.92); stroke: rgba(0, 0, 0, 0.3); }
.map-pin-label { fill: #222222; }
.map-pin-focus .map-pin-body, .map-cluster-dot { fill: #FF6F00; }
.map-pin-focus .map-pin-label-bg { stroke: #FF6F00; }
.map-cluster-ring { fill: rgba(255, 111, 0, 0.25); }
.map-pick-ring, .map-pick-cross { stroke: #FF6F00; }
.map-pins-layer a:hover .map-pin-body, .map-pins a:hover .map-pin-body { fill: #FF6F00; }
.map-scale-line { stroke: #333333; }
.map-scale-text { fill: #333333; stroke: #ffffff; }
.map-attrib { fill: #777777; }
.map-ctrl { background: rgba(255, 255, 255, 0.92) !important; color: #FF6F00 !important; border-color: #cccccc !important; }
.map-ctrl:hover { background: #FF6F00 !important; color: #ffffff !important; border-color: #FF6F00 !important; }
.map-ctrl-off:hover { background: rgba(255, 255, 255, 0.92) !important; color: #FF6F00 !important; border-color: #cccccc !important; }
.map-pick-cell:hover { background: rgba(255, 111, 0, 0.18); outline-color: rgba(255, 111, 0, 0.7); }
.map-place-result, .map-center-link { color: #FF6F00 !important; border-color: #cccccc !important; }
.map-place-result:hover, .map-center-link:hover { background: #FF6F00 !important; color: #ffffff !important; border-color: #FF6F00 !important; }
.map-picked { background: #F0F0F0 !important; color: #FF6F00 !important; }
.map-picked-near { color: #555555 !important; }
.map-markers-list .map-marker-row--focus { background: rgba(255, 111, 0, 0.08) !important; box-shadow: inset 3px 0 0 #FF6F00 !important; }
.map-marker-row--focus .map-marker-idx { background: #FF6F00 !important; color: #ffffff !important; }
.map-marker-label { color: #E65100 !important; }
.map-marker-date { color: #777777 !important; }
.map-marker-coords { color: #222222 !important; }
.map-popup-pointer { fill: #ffffff; stroke: #cccccc; }
.map-stage .map-popup-card { background: #ffffff !important; border: 1px solid #cccccc !important; color: #222222; }
.map-stage .map-popup-text { color: #333333; }
.map-popup-coords { color: #222222; }
.map-stage .map-popup-meta { color: #777777; }
.map-popup-close { color: #777777; }
.map-popup-close:hover { color: #FF6F00; }
.oasis-pager-info { color: #888888; }
.oasis-pager-btn { background: #FFFFFF; color: #555555 !important; border: 1px solid #E0E0E0; text-decoration: none !important; }
.oasis-pager-btn:hover, .oasis-pager-btn.active { border-color: #2C2C2C; color: #2C2C2C !important; text-decoration: none !important; }

View file

@ -210,24 +210,9 @@ footer a:hover {
gap: 9px;
}
.card-tags a.tag-link {
text-decoration: none;
color: #181818;
background: #FFD600;
padding: 5px 13px 4px 13px;
border-radius: 7px;
font-size: .98em;
border: none;
font-weight: bold;
}
.card-tags a.tag-link:hover {
background: #ffe86a;
color: #111;
cursor: pointer;
}
a.user-link {
a.user-link, button.user-link {
background-color: #FFA500;
color: #000;
padding: 8px 16px;
@ -241,14 +226,14 @@ a.user-link {
font-size: 0.8em;
}
a.user-link:hover {
a.user-link:hover, button.user-link:hover {
background-color: #FFD700;
border-color: #FFD700;
color: #000;
cursor: pointer;
}
a.user-link:focus {
a.user-link:focus, button.user-link:focus {
background-color: #007B9F;
border-color: #007B9F;
color: #fff;
@ -316,7 +301,7 @@ a.user-link:focus {
.stats-kpi-value { color: #FFD700 !important; }
.carbon-bar-note, .carbon-bar-formula { color: #FFD700 !important; }
.graphos-node-label { fill: #ddd !important; }
.graphos-node-label-me { fill: #ffa500 !important; }
.graphos-node-label-me { fill: #5dade2 !important; }
.graphos-legend { color: #ddd !important; }
.blockchain-view { background-color: #191b20 !important; color: #FFD700 !important; }
.block { background: #23242a !important; }
@ -333,6 +318,8 @@ a.user-link:focus {
.btn-singleview:hover { background: #2d2e34 !important; color: #FFD700 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #ffa300 !important; color: #000000 !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #ffb733 !important; color: #000000 !important; }
.content-actions .btn-singleview.btn-content { border: 1px solid #ffa300 !important; }
.content-actions .btn-singleview.btn-content:hover { background: rgba(255, 163, 0, .18) !important; border-color: #ffa300 !important; }
.btn-back { background: #21232b !important; color: #ffa300 !important; }
.btn-back:hover { background: #292b36 !important; color: #FFD700 !important; }
.block-info-table td, .pm-info-table td { border-color: #444 !important; }

View file

@ -241,32 +241,23 @@ footer a {
color: #00FF00;
}
.card-tags a.tag-link {
color: #00FF00;
background: #000000;
}
.card-tags a.tag-link:hover {
background: #00FF00;
color: #000000;
cursor: pointer;
}
a.user-link {
a.user-link, button.user-link {
background-color: #00FF00;
color: #000000;
border-color: #00FF00;
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
}
a.user-link:hover {
a.user-link:hover, button.user-link:hover {
background-color: #000000;
border-color: #00FF00;
color: #00FF00;
cursor: pointer;
}
a.user-link:focus {
a.user-link:focus, button.user-link:focus {
background-color: #00FF00;
border-color: #00FF00;
color: #000000;
@ -310,7 +301,7 @@ a.user-link:focus {
.stats-kpi-value { color: #00FF00 !important; }
.carbon-bar-note, .carbon-bar-formula { color: #00FF00 !important; }
.graphos-node-label { fill: #00FF00 !important; }
.graphos-node-label-me { fill: #ffa500 !important; font-weight: bold !important; }
.graphos-node-label-me { fill: #5dade2 !important; font-weight: bold !important; }
.graphos-legend { color: #00FF00 !important; }
.graphos-edge { stroke: #003300 !important; }
/* Blockexplorer */
@ -329,6 +320,8 @@ a.user-link:focus {
.btn-singleview:hover { background: #00FF00 !important; color: #000000 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #00FF00 !important; color: #000000 !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #66FF66 !important; color: #000000 !important; }
.content-actions .btn-singleview.btn-content { border: 1px solid #00FF00 !important; }
.content-actions .btn-singleview.btn-content:hover { background: rgba(0, 255, 0, .18) !important; border-color: #00FF00 !important; }
.btn-back { background: #000000 !important; color: #00FF00 !important; border: 1px solid #00FF00 !important; }
.btn-back:hover { background: #00FF00 !important; color: #000000 !important; }
.block-info-table td, .pm-info-table td { border-color: #00FF00 !important; }
@ -379,4 +372,47 @@ nav, .sidebar-left nav, .sidebar-right nav, .sidebar-left ul, .sidebar-right ul
.ai-nav-result-card a { color: #00FF00 !important; }
.ai-nav-result-card a:hover { background: #00FF00 !important; color: #000000 !important; }
.ai-nav-query { color: #00FF00 !important; }
.trending-card.own-content { box-shadow: inset 3px 0 0 #00FF00; }
.trending-card.own-content, .addr-card.ubi-pub-card.own-content { box-shadow: inset 3px 0 0 #00FF00; }
.map-stage { background: #000000 !important; border-color: #00FF00 !important; }
.map-label-country { fill: #00FF00; stroke: #000000; }
.map-place-dot { fill: #00FF00; stroke: #000000; }
.map-place-capital { fill: #66FF66; }
.map-place-label { fill: #00FF00; stroke: #000000; }
.map-pin-body { fill: #00aa00; stroke: #00FF00; }
.map-pin-main .map-pin-body { fill: #00FF00; stroke: #000000; }
.map-pin-focus .map-pin-body { fill: #ffffff; stroke: #00FF00; }
.map-pin-eye { fill: #000000; }
.map-pin-label-bg { fill: rgba(0, 0, 0, 0.9); stroke: #00FF00; }
.map-pin-focus .map-pin-label-bg { stroke: #ffffff; }
.map-pin-label { fill: #00FF00; }
.map-pins-layer a:hover .map-pin-body, .map-pins a:hover .map-pin-body { fill: #ffffff; }
.map-cluster-ring { fill: rgba(0, 255, 0, 0.25); }
.map-cluster-dot { fill: #00FF00; stroke: #000000; }
.map-pick-ring, .map-pick-cross { stroke: #00FF00; }
.map-scale-line { stroke: #00FF00; }
.map-scale-text { fill: #00FF00; stroke: #000000; }
.map-attrib { fill: #008800; }
.map-ctrl { background: rgba(0, 0, 0, 0.9) !important; color: #00FF00 !important; border-color: #00FF00 !important; }
.map-ctrl:hover { background: #00FF00 !important; color: #000000 !important; }
.map-ctrl-off:hover { background: rgba(0, 0, 0, 0.9) !important; color: #00FF00 !important; }
.map-pick-cell:hover { background: rgba(0, 255, 0, 0.18); outline-color: rgba(0, 255, 0, 0.7); }
.map-place-result, .map-center-link { color: #00FF00 !important; border-color: #00FF00 !important; }
.map-place-result:hover, .map-center-link:hover { background: #00FF00 !important; color: #000000 !important; }
.map-picked { background: #050505 !important; color: #00FF00 !important; }
.map-picked-near { color: #00CC00 !important; }
.map-markers-list .map-marker-row { border-color: #003300 !important; }
.map-markers-list .map-marker-row--focus { background: rgba(0, 255, 0, 0.08) !important; box-shadow: inset 3px 0 0 #00FF00 !important; }
.map-marker-idx { background: #004400 !important; color: #00FF00 !important; }
.map-marker-idx--main, .map-marker-row--focus .map-marker-idx { background: #00FF00 !important; color: #000000 !important; }
.map-marker-label { color: #00FF00 !important; }
.map-marker-date { color: #00AA00 !important; }
.map-popup-pointer { fill: #000000; stroke: #00FF00; }
.map-stage .map-popup-card { background: #000000; border-color: #00FF00; color: #00FF00; }
.map-stage .map-popup-text { color: #00FF00; }
.map-popup-coords { color: #66FF66; }
.map-stage .map-popup-meta { color: #00AA00; }
.map-popup-close { color: #00AA00; }
.map-popup-close:hover { color: #ffffff; }
.oasis-pager-info { color: #008800; }
.oasis-pager-btn { background: #0a0a0a; color: #00CC00; border: 1px solid #00FF00; }
.oasis-pager-btn:hover, .oasis-pager-btn.active { border-color: #00FF00; color: #00FF00; }

View file

@ -277,32 +277,23 @@ header {
color: #B86ADE;
}
.card-tags a.tag-link {
color: #FFFFFF;
background: #D94F4F;
}
.card-tags a.tag-link:hover {
background: #B86ADE;
color: #E5E5E5;
cursor: pointer;
}
a.user-link {
a.user-link, button.user-link {
background-color: #FFD600;
color: #3C1360;
border-color: #FFD600;
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
}
a.user-link:hover {
a.user-link:hover, button.user-link:hover {
background-color: #FFB600;
border-color: #FFB600;
color: #3C1360;
cursor: pointer;
}
a.user-link:focus {
a.user-link:focus, button.user-link:focus {
background-color: #9A2F2F;
border-color: #9A2F2F;
color: #E5E5E5;
@ -346,7 +337,7 @@ a.user-link:focus {
.stats-kpi-value { color: #FFEEDB !important; }
.carbon-bar-note, .carbon-bar-formula { color: #FFEEDB !important; }
.graphos-node-label { fill: #FFEEDB !important; }
.graphos-node-label-me { fill: #ffa500 !important; }
.graphos-node-label-me { fill: #5dade2 !important; }
.graphos-legend { color: #FFEEDB !important; }
/* Blockexplorer */
.blockchain-view { background-color: #2D0B47 !important; color: #FFEEDB !important; }
@ -364,6 +355,8 @@ a.user-link:focus {
.btn-singleview:hover { background: #5A1A85 !important; color: #FFD600 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #B86ADE !important; color: #2A0E42 !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #CE8CE9 !important; color: #2A0E42 !important; }
.content-actions .btn-singleview.btn-content { border: 1px solid #B86ADE !important; }
.content-actions .btn-singleview.btn-content:hover { background: rgba(184, 106, 222, .18) !important; border-color: #B86ADE !important; }
.btn-back { background: #A34AD8 !important; color: #FFFFFF !important; }
.btn-back:hover { background: #751E9F !important; color: #FFFFFF !important; }
.block-info-table td, .pm-info-table td { border-color: #B86ADE !important; }
@ -395,4 +388,41 @@ a.user-link:focus {
.tribe-subtribe-link:hover { background: #5A1A85 !important; }
.tribe-parent-image { border-color: #B86ADE !important; }
.tribe-parent-box { background: #3C1360 !important; }
.trending-card.own-content { box-shadow: inset 3px 0 0 #B86ADE; }
.trending-card.own-content, .addr-card.ubi-pub-card.own-content { box-shadow: inset 3px 0 0 #B86ADE; }
.map-stage { background: #2a0640 !important; border-color: #9B1C96 !important; }
.map-label-country { fill: #E5E5E5; stroke: #2a0640; }
.map-place-dot { fill: #ffffff; stroke: #2a0640; }
.map-place-capital { fill: #B86ADE; }
.map-place-label { fill: #E5E5E5; stroke: #2a0640; }
.map-pin-focus .map-pin-body, .map-cluster-dot { fill: #B86ADE; }
.map-pin-focus .map-pin-label-bg { stroke: #B86ADE; }
.map-pins-layer a:hover .map-pin-body, .map-pins a:hover .map-pin-body { fill: #B86ADE; }
.map-cluster-ring { fill: rgba(184, 106, 222, 0.28); }
.map-pick-ring, .map-pick-cross { stroke: #B86ADE; }
.map-scale-text { stroke: #2a0640; }
.map-attrib { fill: #9B7CAA; }
.map-ctrl { background: rgba(43, 10, 70, 0.9) !important; color: #E5E5E5 !important; border-color: #9B1C96 !important; }
.map-ctrl:hover { background: #B86ADE !important; color: #000000 !important; border-color: #B86ADE !important; }
.map-ctrl-off:hover { background: rgba(43, 10, 70, 0.9) !important; color: #E5E5E5 !important; border-color: #9B1C96 !important; }
.map-pick-cell, .map-pick-cell:hover { border: 0 !important; padding: 0 !important; border-radius: 0 !important; box-shadow: none !important; }
.map-pick-cell { background: transparent !important; }
.map-pick-cell:hover { background: rgba(184, 106, 222, 0.22) !important; outline-color: rgba(184, 106, 222, 0.7); }
.map-place-result, .map-center-link { color: #E5E5E5 !important; border-color: #9B1C96 !important; }
.map-place-result:hover, .map-center-link:hover { background: #B86ADE !important; color: #000000 !important; border-color: #B86ADE !important; }
.map-picked { background: #3C1360 !important; color: #E5E5E5 !important; }
.map-picked-near { color: #C8C8C8 !important; }
.map-markers-list .map-marker-row { border-color: #5A1A85 !important; }
.map-markers-list .map-marker-row--focus { background: rgba(184, 106, 222, 0.1) !important; box-shadow: inset 3px 0 0 #B86ADE !important; }
.map-marker-row--focus .map-marker-idx { background: #B86ADE !important; color: #000000 !important; }
.map-marker-label { color: #B86ADE !important; }
.map-marker-date { color: #C8C8C8 !important; }
.map-popup-pointer { fill: #3C1360; stroke: #9B1C96; }
.map-stage .map-popup-card { background: #3C1360; border-color: #9B1C96; color: #E5E5E5; }
.map-stage .map-popup-text { color: #E5E5E5; }
.map-popup-coords { color: #ffffff; }
.map-stage .map-popup-meta { color: #C8C8C8; }
.map-popup-close { color: #C8C8C8; }
.map-popup-close:hover { color: #B86ADE; }
.oasis-pager-info { color: #9B7CAA; }
.oasis-pager-btn { background: #39006D; color: #C8C8C8; border: 1px solid #9B1C96; }
.oasis-pager-btn:hover, .oasis-pager-btn.active { border-color: #E5E5E5; color: #E5E5E5; }

View file

@ -1,15 +1,22 @@
const path = require('path');
let i18n = {};
const languages = ['en', 'es', 'fr', 'eu', 'de', 'it', 'pt', 'zh', 'ar', 'hi', 'ru'];
const i18n = {};
const languages = ['en', 'es', 'ca', 'gl', 'fr', 'eu', 'de', 'it', 'pt', 'zh', 'ar', 'hi', 'ru'];
languages.forEach(language => {
try {
const languagePath = path.join(__dirname, `oasis_${language}.js`);
const languageData = require(languagePath);
i18n[language] = languageData[language];
} catch (error) {
console.error(`Failed to load language file for ${language}:`, error);
}
Object.defineProperty(i18n, language, {
enumerable: true,
configurable: true,
get() {
let languageData;
try {
languageData = require(path.join(__dirname, `oasis_${language}.js`))[language];
} catch (error) {
console.error(`Failed to load language file for ${language}:`, error);
}
Object.defineProperty(i18n, language, { value: languageData, enumerable: true, configurable: true, writable: true });
return languageData;
}
});
});
try {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -10,10 +10,13 @@ const { printMetadata } = require('../server/ssb_metadata');
const updateFlagPath = path.join(__dirname, "../server/.update_required");
let internalSSB = null;
try {
const { server } = require('../server/SSB_server');
internalSSB = server;
} catch {}
let internalOpen = null;
if (!process.env.OASIS_TEST) {
try {
const SSB_server = require('../server/SSB_server');
internalOpen = () => SSB_server.open().then((srv) => { internalSSB = srv; return srv; });
} catch {}
}
if (process.env.OASIS_TEST) {
ssbConfig.path = fs.mkdtempSync(path.join(os.tmpdir(), "oasis-"));
@ -24,10 +27,33 @@ const socketPath = path.join(ssbConfig.path, "socket");
const publicInteger = ssbConfig.keys.public.replace(".ed25519", "");
const remote = `unix:${socketPath}~noauth:${publicInteger}`;
const windowLogStream = (ssb) => {
if (!ssb || ssb._logStreamWindowed || typeof ssb.createLogStream !== "function") return ssb;
const pull = require("../server/node_modules/pull-stream");
const defer = require("../server/node_modules/pull-defer");
const orig = ssb.createLogStream;
ssb.createLogStream = function (opts) {
const o = opts || {};
const plain = o.limit && !o.reverse && !o.live && !o.raw && o.old === undefined && !o.gt && !o.lt;
if (!plain) return orig.call(ssb, opts);
const src = defer.source();
pull(
orig.call(ssb, { ...o, reverse: true }),
pull.collect((err, msgs) => {
if (err) return src.abort(err);
src.resolve(pull.values(msgs.reverse()));
})
);
return src;
};
ssb._logStreamWindowed = true;
return ssb;
};
const connect = (options) =>
new Promise((resolve, reject) => {
ssbClient(process.env.OASIS_TEST ? ssbConfig.keys : null, options)
.then(resolve)
.then((ssb) => resolve(windowLogStream(ssb)))
.catch(reject);
});
@ -89,8 +115,15 @@ module.exports = ({ offline, port = 3000, host = 'localhost', isPublic = false }
return new Promise((resolve, reject) => {
if (internalSSB) {
const { printMetadata, colors } = require('../server/ssb_metadata');
printMetadata('OASIS GUI', colors.yellow, port, host, offline, isPublic);
return resolve(internalSSB);
printMetadata('OASIS UX', colors.yellow, port, host, offline, isPublic);
return resolve(windowLogStream(internalSSB));
}
if (internalOpen) {
return internalOpen().then((srv) => {
const { printMetadata, colors } = require('../server/ssb_metadata');
printMetadata('OASIS UX', colors.yellow, port, host, offline, isPublic);
resolve(windowLogStream(srv));
}).catch(reject);
}
if (clientHandle && clientHandle.closed === false) {
@ -105,7 +138,7 @@ module.exports = ({ offline, port = 3000, host = 'localhost', isPublic = false }
reject(new Error("Closing Oasis"));
} else {
const { printMetadata, colors } = require('../server/ssb_metadata');
printMetadata('OASIS GUI', colors.yellow, port, host, offline, isPublic);
printMetadata('OASIS UX', colors.yellow, port, host, offline, isPublic);
resolve(ssb);
}
}).catch(reject);

View file

@ -8,20 +8,21 @@ const mount = require(path.join(__dirname, "../server/node_modules/koa-mount"));
function obfuscateClearnetHtml(html) {
if (typeof html !== 'string' || html.length === 0) return html;
const preserve = [];
const tag = require('crypto').randomBytes(12).toString('hex');
const stash = (re) => {
html = html.replace(re, (m) => {
preserve.push(m);
return `${preserve.length - 1}`;
return `\u0001${tag}:${preserve.length - 1}\u0001`;
});
};
stash(/<pre[\s\S]*?<\/pre>/gi);
stash(/<textarea[\s\S]*?<\/textarea>/gi);
stash(/<style[\s\S]*?<\/style>/gi);
html = html.replace(/<!--[\s\S]*?-->/g, '');
html = html.replace(/>[\s\n\r\t]+</g, '><');
html = html.replace(/>[ \t]*[\r\n][\s]*</g, '><');
html = html.replace(/[ \t]{2,}/g, ' ');
html = html.replace(/[\r\n]+/g, '');
html = html.replace(/(\d+)/g, (_, i) => preserve[Number(i)] || '');
html = html.replace(new RegExp(`\\u0001${tag}:(\\d+)\\u0001`, 'g'), (_, i) => preserve[Number(i)] || '');
return html;
}
@ -42,42 +43,17 @@ const collectLocalIPs = () => {
module.exports = ({ host, port, middleware, allowHost }) => {
const assets = new Koa()
assets.use(koaStatic(join(__dirname, "..", "client", "assets"), { maxage: 60 * 60 * 1000 }));
assets.use(async (ctx, next) => {
ctx.set("Cache-Control", ctx.query && ctx.query.v ? "public, max-age=31536000, immutable" : "public, max-age=3600");
await next();
});
assets.use(koaStatic(join(__dirname, "..", "client", "assets")));
const app = new Koa();
const validHosts = [];
const isClearnetPath = (request) => {
const url = String(request.url || '');
return url === '/c' || url.startsWith('/c/') || url.startsWith('/c?');
};
const isValidRequest = (request) => {
if (isClearnetPath(request)) return request.method === 'GET';
if (validHosts.includes(request.hostname) !== true) {
return false;
}
if (request.method !== "GET") {
if (request.header.referer == null) {
return false;
}
try {
const refererUrl = new URL(request.header.referer);
if (validHosts.includes(refererUrl.hostname) !== true) {
return false;
}
if (refererUrl.pathname.startsWith("/blob/")) {
return false;
}
} catch (e) {
return false;
}
}
return true;
};
const { isClearnetPath, isTrustedRequest, buildCsp } = require(path.join(__dirname, "..", "backend", "request_guards"));
const isValidRequest = (request) => isTrustedRequest(request, validHosts);
const httpDebug = process.argv.includes('--debug') || process.env.OASIS_DEBUG === '1' || process.env.OASIS_DEBUG === 'true';
@ -98,17 +74,21 @@ module.exports = ({ host, port, middleware, allowHost }) => {
});
app.use(mount("/assets", assets));
app.use(mount("/c/assets", assets));
const maptiles = new Koa();
maptiles.use(koaStatic(join(__dirname, "..", "maps", "tiles")));
app.use(mount("/maptiles", maptiles));
const mapcache = new Koa();
mapcache.use(koaStatic(join(__dirname, "..", "maps", "cache")));
app.use(mount("/mapcache", mapcache));
const mapTiles = new Koa();
mapTiles.use(koaStatic(join(__dirname, "..", "maps", "tiles"), { maxage: 30 * 24 * 60 * 60 * 1000, immutable: true }));
app.use(mount("/maptiles", mapTiles));
app.use(mount("/c/maptiles", mapTiles));
const gamesStatic = new Koa();
gamesStatic.use(async (ctx, next) => {
ctx.set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' data: blob: mediastream:; connect-src 'none'; form-action 'none'; base-uri 'none'; object-src 'none'; frame-ancestors 'self'");
ctx.set("X-Content-Type-Options", "nosniff");
ctx.set("X-Frame-Options", "SAMEORIGIN");
ctx.set("Referrer-Policy", "same-origin");
await next();
});
gamesStatic.use(koaStatic(join(__dirname, "..", "games")));
app.use(mount("/game-assets", gamesStatic));
@ -120,34 +100,7 @@ module.exports = ({ host, port, middleware, allowHost }) => {
if (httpDebug) console.log(`[http] ${ctx.method} ${ctx.path}`);
const isClearnet = isClearnetPath(ctx.request);
const csp = isClearnet
? [
"default-src 'self'",
"script-src 'none'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data:",
"media-src 'self' blob:",
"connect-src 'self'",
"form-action 'self'",
"object-src 'none'",
"base-uri 'none'",
"frame-ancestors 'none'"
].join("; ")
: [
"default-src 'self'",
"script-src 'self' http://localhost:3000/js",
"style-src 'self'",
"img-src 'self'",
"media-src 'self' blob:",
"worker-src 'self' blob:",
"frame-src 'self'",
"form-action 'self'",
"object-src 'none'",
"base-uri 'none'",
"frame-ancestors 'none'"
].join("; ");
ctx.set("Content-Security-Policy", csp);
ctx.set("Content-Security-Policy", buildCsp(isClearnet, { frames: ctx.method === "GET" && /^\/games\/[a-z0-9]+\/?$/.test(ctx.path) }));
ctx.set("X-Frame-Options", "SAMEORIGIN");
ctx.set("X-Content-Type-Options", "nosniff");
@ -155,12 +108,10 @@ module.exports = ({ host, port, middleware, allowHost }) => {
ctx.set("Referrer-Policy", "same-origin");
ctx.set("Permissions-Policy", "speaker=(self)");
const validHostsString = validHosts.join(" or ");
ctx.assert(
isValidRequest(ctx.request),
400,
`Request must be addressed to ${validHostsString} and non-GET requests must contain non-blob referer.`
"Request must be addressed to this node and non-GET requests must come from its own pages."
);
await next();
@ -173,13 +124,10 @@ module.exports = ({ host, port, middleware, allowHost }) => {
}
});
// pdf viewer
const pdfjsPath = path.join(__dirname, '../server/node_modules/pdfjs-dist/build/pdf.min.js');
app.use(koaStatic(pdfjsPath));
middleware.forEach((m) => app.use(m));
const server = app.listen({ host, port });
const server = require("http").createServer({ maxHeaderSize: 256 * 1024 }, app.callback()).listen({ host, port });
server.on("listening", () => {
const address = server.address();

View file

@ -1,115 +0,0 @@
ECOin - Copyright (c) - 2014/2025 - GPLv3 - epsylon@riseup.net (https://ecoin.03c8.net)
===========================================
# SOURCES for P2P Crypto-Currency (ECOin) #
===========================================
Testing machine is: Debian GNU/Linux 12 (bookworm) (x86_64).
All of the commands should be executed in a shell.
------------------------------
(0.) Clone the github tree to get the source code:
+ Official:
git clone http://code.03c8.net/epsylon/ecoin
+ Mirror:
git clone https://github.com/epsylon/ecoin
------------------------------
===================================================
# SERVER -ecoind- for P2P Crypto-Currency (ECOin) #
===================================================
(0.) Version libraries:
- Libboost -> source code 1.68 provided at: src/boost_1_68_0
(1.) Install dependencies:
sudo apt-get install build-essential libssl-dev libssl3 libdb5.3-dev libdb5.3++-dev libleveldb-dev miniupnpc libminiupnpc-dev
+ Optionally install qrencode (and set USE_QRCODE=1):
sudo apt-get install libqrencode-dev
(2.) Now you should be able to build ecoind:
cd src/
make -f makefile.linux USE_UPNP=- USE_IPV6=-
strip ecoind
An executable named 'ecoind' will be built.
Now you can launch: ./ecoind to run your ECOin server.
------------------------------
============================================
# WALLET for P2P Crypto-Currency (ECOin) #
============================================
(0.) Version libraries:
- Libboost -> source code 1.68 provided at: src/boost_1_68_0
(1.) First, make sure that the required packages for Qt5 development (an the others required for building the daemon) are installed:
sudo apt-get install qt5-qmake qtbase5-dev build-essential libssl-dev libssl3 libdb5.3-dev libdb5.3++-dev libleveldb-dev miniupnpc libminiupnpc-dev
+ Optionally install qrencode (and set USE_QRCODE=1):
sudo apt-get install libqrencode-dev
(2.) Then execute the following:
qmake USE_UPNP=- USE_IPV6=-
make
An executable named 'ecoin-qt' will be built.
Now you can launch: ./ecoin-qt to run your ECOin wallet/GUI.
------------------------------
========================================
+ CPU MINER for ECOin (Unix/GNU-Linux) #
========================================
See doc/MINING.txt for detailed instructions on running /ecoin-miner/ on different platforms.
+ GNU/Linux:
cd miner/
sh build.sh
An executable named 'cpuminer' will be built.
Now you can launch: ./cpuminer to run your ECOin PoW miner.
======================================
For a list of command-line options:
./ecoind --help
To start the ECOin daemon:
./ecoind -daemon
For ECOin-QT Wallet
./ecoin-qt
For debugging:
tail -f /home/$USER/.ecoin/debug.log
======================================

View file

@ -1,32 +1,68 @@
document.addEventListener('DOMContentLoaded', () => {
if (typeof pdfjsLib === 'undefined') return;
pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.min.mjs';
const showPdfFallback = () => {
document.querySelectorAll('.pdf-viewer-container').forEach(container => {
if (container.dataset.pdfReady) return;
container.dataset.pdfReady = '1';
container.textContent = '';
const url = container.getAttribute('data-pdf-url');
if (url) {
const link = document.createElement('a');
link.href = url;
link.textContent = '📄 PDF';
container.appendChild(link);
}
});
};
const initPdfViewers = async () => {
let pdfjsLib;
try {
pdfjsLib = await import('/js/pdf.min.mjs?v=102');
pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.min.mjs?v=102';
} catch (err) {
showPdfFallback();
return;
}
document.querySelectorAll('.pdf-viewer-container').forEach(async container => {
const pdfUrl = container.getAttribute('data-pdf-url');
if (!pdfUrl) return;
if (!pdfUrl || container.dataset.pdfReady) return;
container.dataset.pdfReady = '1';
let pdf;
try {
pdf = await pdfjsLib.getDocument(pdfUrl).promise;
} catch (err) {
container.textContent = '';
const fallback = document.createElement('a');
fallback.href = pdfUrl;
fallback.textContent = '📄 PDF';
container.appendChild(fallback);
return;
}
const pdf = await pdfjsLib.getDocument(pdfUrl).promise;
let currentPage = 1;
let scale = 1.5;
let rotation = 0;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const canvasWrap = document.createElement('div');
canvasWrap.className = 'pdf-canvas-wrap';
canvasWrap.appendChild(canvas);
container.innerHTML = '';
container.appendChild(canvas);
container.appendChild(canvasWrap);
const controls = document.createElement('div');
controls.className = 'pdf-controls';
controls.innerHTML = `
<button id="prev">⬅️</button>
<button id="next">➡️</button>
<button id="zoomIn">🔍+</button>
<button id="zoomOut">🔍−</button>
<button id="rotate">↻</button>
<button id="download">⬇️</button>
<button id="fullscreen">🔲</button>
<button id="metadata">ℹ️</button>
<button class="pdf-prev">⬅️</button>
<button class="pdf-next">➡️</button>
<button class="pdf-zoom-in">🔍+</button>
<button class="pdf-zoom-out">🔍−</button>
<button class="pdf-rotate">↻</button>
<button class="pdf-download">⬇️</button>
<button class="pdf-fullscreen">🔲</button>
<button class="pdf-metadata">ℹ️</button>
`;
container.appendChild(controls);
@ -48,29 +84,48 @@ document.addEventListener('DOMContentLoaded', () => {
}
};
try {
const firstPage = await pdf.getPage(1);
const baseViewport = firstPage.getViewport({ scale: 1, rotation: 0 });
const avail = canvasWrap.clientWidth || container.clientWidth;
if (avail > 0 && baseViewport.width > 0) {
scale = Math.min(1.5, Math.max(0.5, (avail - 40) / baseViewport.width));
}
} catch (e) {}
renderPage(currentPage);
controls.querySelector('#prev').onclick = () => goToPage(-1);
controls.querySelector('#next').onclick = () => goToPage(1);
controls.querySelector('#zoomIn').onclick = () => { scale += 0.2; renderPage(currentPage); };
controls.querySelector('#zoomOut').onclick = () => { scale = Math.max(0.5, scale - 0.2); renderPage(currentPage); };
controls.querySelector('#rotate').onclick = () => { rotation = (rotation + 90) % 360; renderPage(currentPage); };
controls.querySelector('#download').onclick = () => {
controls.querySelector('.pdf-prev').onclick = () => goToPage(-1);
controls.querySelector('.pdf-next').onclick = () => goToPage(1);
controls.querySelector('.pdf-zoom-in').onclick = () => { scale += 0.2; renderPage(currentPage); };
controls.querySelector('.pdf-zoom-out').onclick = () => { scale = Math.max(0.5, scale - 0.2); renderPage(currentPage); };
controls.querySelector('.pdf-rotate').onclick = () => { rotation = (rotation + 90) % 360; renderPage(currentPage); };
controls.querySelector('.pdf-download').onclick = () => {
const a = document.createElement('a');
a.href = pdfUrl;
a.download = 'document.pdf';
a.click();
};
controls.querySelector('#fullscreen').onclick = () => {
if (canvas.requestFullscreen) canvas.requestFullscreen();
else if (canvas.webkitRequestFullscreen) canvas.webkitRequestFullscreen();
else if (canvas.mozRequestFullScreen) canvas.mozRequestFullScreen();
else if (canvas.msRequestFullscreen) canvas.msRequestFullscreen();
controls.querySelector('.pdf-fullscreen').onclick = async () => {
const maximized = container.classList.toggle('pdf-maximized');
document.body.classList.toggle('pdf-maximized-body', maximized);
try {
const p1 = await pdf.getPage(currentPage);
const vw1 = p1.getViewport({ scale: 1, rotation });
const avail = Math.max(260, (maximized ? window.innerWidth : (canvasWrap.clientWidth || container.clientWidth || 360)) - 24);
scale = maximized ? avail / vw1.width : Math.min(1.5, avail / vw1.width);
await renderPage(currentPage);
} catch (_) {}
};
controls.querySelector('#metadata').onclick = async () => {
controls.querySelector('.pdf-metadata').onclick = async () => {
const info = await pdf.getMetadata();
alert(`Title: ${info.info.Title || 'N/A'}\nAuthor: ${info.info.Author || 'N/A'}\nPDF Producer: ${info.info.Producer || 'N/A'}`);
};
});
});
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPdfViewers);
} else {
initPdfViewers();
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long