Защита рецептов: SQL DEPO/SPECTRE/QUIK вынесен в пакет fsql под garble
Реализация варианта B из аудита защиты знаний. Прямой garble всего bj-server ломает html/template (он обращается к полям структур по имени, garble их переименовывает). Решение — селективная обфускация: GOGARBLE обфусцирует ТОЛЬКО пакет с секретами, шаблоны и обработчики не затрагиваются. 95 SQL-запросов к DEPO/SPECTRE/QUIK и трансферным таблицам FTV_M2M вынесены из lkgateway в отдельный пакет internal/lkgateway/fsql как переменные (именно var, не const: const компилятор вставил бы обратно в необфусцируемый пакет, и шифрование бы не сработало — проверено). Сами обработчики, типы и параметры sql.Named остались на месте; пакет держит только строки запросов. build-release.sh собирает bj-server с `GOGARBLE=.../fsql garble -literals` (нужен отдельный SDK go1.26 — модуль-кэшный тулчейн garble не подходит); если garble/go1.26 не найдены — обычная сборка с предупреждением. Проверено на реальном garble-бинаре (запускается, /admin и страницы на структурах работают): рецепт чтения чужих систем из бинаря исчез — OD_RESTS 13→0, OD_WIRING 5→0, OD_TURNS 1→0, OD_BALANCES 3→0, D_B_CONTRACTS 1→0, OD_CLIENTS_PORTS 10→0, DepoLimits/MoneyLimits →0. Остаток FTV_M2M — упоминания имён таблиц в операторских embed-шаблонах и логах, не сам рецепт. Стенд собран обычной сборкой (без garble) — трассировки остаются читаемыми. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/lkgateway/fsql"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -63,15 +64,7 @@ func lkArchivePortfolio(ctx context.Context, s FancyMSSQLSettings, contract stri
|
||||
today := time.Now()
|
||||
isPast := day.Before(time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, time.UTC))
|
||||
|
||||
rows, err := conn.QueryContext(cctx, `SELECT r.ID, b.NUM_S, ISNULL(b.SYS_NAME,''), b.NUM_1, ISNULL(r.REG_2,0), ISNULL(r.VALUE_ID,0),
|
||||
CAST(ISNULL(r.A,0) AS float), CAST(ISNULL(r.D,0) AS float), CAST(ISNULL(r.EQ_D,0) AS float),
|
||||
ISNULL(vs.ISIN,''), ISNULL(vs.NAME,''), ISNULL(vc.SYSNAME,''), ISNULL(sh.CLASS,0), CAST(ISNULL(sh.NOMINAL,0) AS float)
|
||||
FROM OD_RESTS r JOIN OD_BALANCES b ON b.ID = r.BAL_ACC
|
||||
LEFT JOIN OD_VALUES vs ON vs.ID = r.REG_2
|
||||
LEFT JOIN OD_VALUES vc ON vc.ID = r.VALUE_ID
|
||||
LEFT JOIN OD_SHARES sh ON sh.ID = r.REG_2
|
||||
WHERE r.REG_3 = @c AND b.IS_BAL = 1 AND b.PART = 39 AND b.NUM_1 IN (50,51,52,55,58)
|
||||
ORDER BY b.NUM_1, vs.NAME`, sql.Named("c", c.DOC))
|
||||
rows, err := conn.QueryContext(cctx, fsql.Arch01, sql.Named("c", c.DOC))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("остатки: %v", err)
|
||||
}
|
||||
@@ -91,12 +84,7 @@ func lkArchivePortfolio(ctx context.Context, s FancyMSSQLSettings, contract stri
|
||||
for _, r := range rests {
|
||||
ids = append(ids, fmt.Sprint(r.id))
|
||||
}
|
||||
trows, err := conn.QueryContext(cctx, fmt.Sprintf(`SELECT REST,
|
||||
CAST(SUM(CASE WHEN TYPE_ = 1 THEN AMOUNT_ ELSE -AMOUNT_ END) AS float),
|
||||
CAST(SUM(CASE WHEN TYPE_ = 1 THEN VALUE_ ELSE -VALUE_ END) AS float),
|
||||
CAST(SUM(CASE WHEN TYPE_ = 1 THEN EQ_ ELSE -EQ_ END) AS float)
|
||||
FROM OD_TURNS WHERE REST IN (%s) AND WIRDATE >= @d AND IS_PLAN = 'F' AND YEAR(WIRDATE) < 9000
|
||||
GROUP BY REST`, strings.Join(ids, ",")), sql.Named("d", day.AddDate(0, 0, 1)))
|
||||
trows, err := conn.QueryContext(cctx, fmt.Sprintf(fsql.Arch02, strings.Join(ids, ",")), sql.Named("d", day.AddDate(0, 0, 1)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("обороты: %v", err)
|
||||
}
|
||||
@@ -209,7 +197,7 @@ func spectreAsOf(ctx context.Context, conn *sql.DB) time.Time {
|
||||
return spectreAsOfCache.v
|
||||
}
|
||||
var d sql.NullTime
|
||||
_ = conn.QueryRowContext(ctx, `SELECT MAX(R_DATE) FROM OD_DOCS WHERE YEAR(R_DATE) < 9000`).Scan(&d)
|
||||
_ = conn.QueryRowContext(ctx, fsql.Arch03).Scan(&d)
|
||||
v := time.Time{}
|
||||
if d.Valid {
|
||||
v = time.Date(d.Time.Year(), d.Time.Month(), d.Time.Day(), 0, 0, 0, 0, time.UTC)
|
||||
@@ -253,9 +241,7 @@ func spectreKind(class int) string {
|
||||
func spectreQuote(ctx context.Context, conn *sql.DB, secID int64, day time.Time) (float64, int) {
|
||||
var ofic sql.NullTime
|
||||
var rate3, pfr, closeP sql.NullFloat64
|
||||
err := conn.QueryRowContext(ctx, `SELECT TOP 1 OFICDATE, CAST(RATE3 AS float), CAST(PFR_PRICE AS float), CAST(CLOSE_ AS float)
|
||||
FROM OD_VALUES_RATES WHERE VALUE_ID = @v AND OFICDATE <= @d AND (RATE3 > 0 OR PFR_PRICE > 0 OR CLOSE_ > 0)
|
||||
ORDER BY OFICDATE DESC`, sql.Named("v", secID), sql.Named("d", day.AddDate(0, 0, 1))).Scan(&ofic, &rate3, &pfr, &closeP)
|
||||
err := conn.QueryRowContext(ctx, fsql.Arch04, sql.Named("v", secID), sql.Named("d", day.AddDate(0, 0, 1))).Scan(&ofic, &rate3, &pfr, &closeP)
|
||||
if err != nil {
|
||||
return 0, 1 << 30
|
||||
}
|
||||
@@ -287,7 +273,7 @@ func spectreFx(ctx context.Context, conn *sql.DB, day time.Time) func(curID int6
|
||||
return v
|
||||
}
|
||||
var rate sql.NullFloat64
|
||||
_ = conn.QueryRowContext(ctx, `SELECT TOP 1 CAST(RATE AS float) FROM OD_VALUES_RATES WHERE VALUE_ID = @v AND MARKET = 0 AND OFICDATE <= @d AND RATE > 0 ORDER BY OFICDATE DESC`,
|
||||
_ = conn.QueryRowContext(ctx, fsql.Arch05,
|
||||
sql.Named("v", curID), sql.Named("d", day.AddDate(0, 0, 1))).Scan(&rate)
|
||||
v := rate.Float64
|
||||
if v <= 0 {
|
||||
@@ -355,8 +341,7 @@ func lkArchiveOperationsLoad(ctx context.Context, s FancyMSSQLSettings, contract
|
||||
cctx, cancel := context.WithTimeout(ctx, 40*time.Second)
|
||||
defer cancel()
|
||||
// Счета бумаг (ПОРТФЕЛЬ) и денег (касса) договора.
|
||||
rows, err := conn.QueryContext(cctx, `SELECT r.ID, b.NUM_1, ISNULL(b.SYS_NAME,'') FROM OD_RESTS r JOIN OD_BALANCES b ON b.ID = r.BAL_ACC
|
||||
WHERE r.REG_3 = @c AND b.PART = 39 AND ((b.NUM_1 = 58 AND b.SYS_NAME LIKE N'ПОРТФЕЛЬ%') OR b.NUM_1 IN (50,51,52,55))`, sql.Named("c", c.DOC))
|
||||
rows, err := conn.QueryContext(cctx, fsql.Arch06, sql.Named("c", c.DOC))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -404,29 +389,7 @@ func lkArchiveOperationsLoad(ctx context.Context, s FancyMSSQLSettings, contract
|
||||
// разбирать список счетов на каждой строке журнала — год данных читался
|
||||
// 6–7 секунд, сейчас — десятки миллисекунд (оба индекса по D_REST/K_REST
|
||||
// с WIRDATE отрабатывают поиском).
|
||||
wrows, err := conn.QueryContext(cctx, fmt.Sprintf(`
|
||||
WITH w AS (
|
||||
SELECT wr.WIRDATE, wr.EQ_, wr.D_REST, wr.K_REST, wr.D_SUMMA, wr.K_SUMMA, wr.D_AMOUNT, wr.K_AMOUNT, wr.NAME,
|
||||
wr.D_REST AS sec_rest, wr.K_REST AS money_rest
|
||||
FROM OD_WIRING wr
|
||||
WHERE wr.D_REST IN (%[1]s) AND wr.IS_PLAN = 'F' AND YEAR(wr.WIRDATE) < 9000
|
||||
AND wr.WIRDATE >= @f AND wr.WIRDATE < @t AND (wr.D_AMOUNT <> 0 OR wr.K_AMOUNT <> 0)
|
||||
UNION ALL
|
||||
SELECT wr.WIRDATE, wr.EQ_, wr.D_REST, wr.K_REST, wr.D_SUMMA, wr.K_SUMMA, wr.D_AMOUNT, wr.K_AMOUNT, wr.NAME,
|
||||
wr.K_REST, wr.D_REST
|
||||
FROM OD_WIRING wr
|
||||
WHERE wr.K_REST IN (%[1]s) AND wr.D_REST NOT IN (%[1]s) AND wr.IS_PLAN = 'F' AND YEAR(wr.WIRDATE) < 9000
|
||||
AND wr.WIRDATE >= @f AND wr.WIRDATE < @t AND (wr.D_AMOUNT <> 0 OR wr.K_AMOUNT <> 0))
|
||||
SELECT w.WIRDATE, CAST(ISNULL(w.EQ_,0) AS float), w.D_REST, w.K_REST,
|
||||
CAST(ISNULL(w.D_SUMMA,0) AS float), CAST(ISNULL(w.K_SUMMA,0) AS float),
|
||||
CAST(ISNULL(w.D_AMOUNT,0) AS float), CAST(ISNULL(w.K_AMOUNT,0) AS float),
|
||||
ISNULL(w.NAME,''), ISNULL(sv.NAME,''), ISNULL(sv.ISIN,''), ISNULL(mv.SYSNAME,'')
|
||||
FROM w
|
||||
LEFT JOIN OD_RESTS sr ON sr.ID = w.sec_rest
|
||||
LEFT JOIN OD_VALUES sv ON sv.ID = sr.REG_2
|
||||
LEFT JOIN OD_RESTS mr ON mr.ID = w.money_rest
|
||||
LEFT JOIN OD_VALUES mv ON mv.ID = mr.VALUE_ID
|
||||
ORDER BY w.WIRDATE`, in), sql.Named("f", fromDay), sql.Named("t", toEnd))
|
||||
wrows, err := conn.QueryContext(cctx, fmt.Sprintf(fsql.Arch07, in), sql.Named("f", fromDay), sql.Named("t", toEnd))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("проводки: %v", err)
|
||||
}
|
||||
@@ -501,14 +464,7 @@ func spectreCashOps(ctx context.Context, conn *sql.DB, cashIDs []string, fromDay
|
||||
}
|
||||
var out []LKOperationRow
|
||||
in := strings.Join(cashIDs, ",")
|
||||
crows, err := conn.QueryContext(ctx, fmt.Sprintf(`SELECT w.WIRDATE, CAST(ISNULL(w.EQ_,0) AS float), w.D_REST, w.K_REST,
|
||||
CAST(ISNULL(w.D_SUMMA,0) AS float), CAST(ISNULL(w.K_SUMMA,0) AS float), ISNULL(w.NAME,''), ISNULL(mv.SYSNAME,'')
|
||||
FROM OD_WIRING w
|
||||
JOIN OD_RESTS mr ON mr.ID = CASE WHEN w.D_REST IN (%[1]s) THEN w.D_REST ELSE w.K_REST END
|
||||
LEFT JOIN OD_VALUES mv ON mv.ID = mr.VALUE_ID
|
||||
WHERE (w.D_REST IN (%[1]s) OR w.K_REST IN (%[1]s)) AND w.IS_PLAN = 'F' AND YEAR(w.WIRDATE) < 9000
|
||||
AND w.WIRDATE >= @f AND w.WIRDATE < @t
|
||||
ORDER BY w.WIRDATE`, in), sql.Named("f", fromDay), sql.Named("t", toEnd))
|
||||
crows, err := conn.QueryContext(ctx, fmt.Sprintf(fsql.Arch08, in), sql.Named("f", fromDay), sql.Named("t", toEnd))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -571,7 +527,7 @@ func spectreDealKind(name string, onDebit bool) string {
|
||||
// spectreProceeds — выручка от продаж по (ISIN|день): [сумма в валюте, сумма в рублях].
|
||||
func spectreProceeds(ctx context.Context, conn *sql.DB, doc int64, from, to time.Time) map[string][2]float64 {
|
||||
out := map[string][2]float64{}
|
||||
rows, err := conn.QueryContext(ctx, `SELECT r.ID FROM OD_RESTS r JOIN OD_BALANCES b ON b.ID = r.BAL_ACC WHERE r.REG_3 = @c AND b.SYS_NAME = N'ВЫРУЧКА'`, sql.Named("c", doc))
|
||||
rows, err := conn.QueryContext(ctx, fsql.Arch09, sql.Named("c", doc))
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
@@ -589,22 +545,7 @@ func spectreProceeds(ctx context.Context, conn *sql.DB, doc int64, from, to time
|
||||
return out
|
||||
}
|
||||
in := strings.Join(ids, ",")
|
||||
wrows, err := conn.QueryContext(ctx, fmt.Sprintf(`
|
||||
WITH w AS (
|
||||
SELECT wr.WIRDATE, wr.EQ_, wr.D_REST, wr.K_REST, wr.D_SUMMA, wr.K_SUMMA, wr.D_REST AS sec_rest
|
||||
FROM OD_WIRING wr
|
||||
WHERE wr.K_REST IN (%[1]s) AND wr.IS_PLAN = 'F' AND YEAR(wr.WIRDATE) < 9000
|
||||
AND wr.WIRDATE >= @f AND wr.WIRDATE < @t AND wr.EQ_ <> 0
|
||||
UNION ALL
|
||||
SELECT wr.WIRDATE, wr.EQ_, wr.D_REST, wr.K_REST, wr.D_SUMMA, wr.K_SUMMA, wr.K_REST
|
||||
FROM OD_WIRING wr
|
||||
WHERE wr.D_REST IN (%[1]s) AND wr.K_REST NOT IN (%[1]s) AND wr.IS_PLAN = 'F' AND YEAR(wr.WIRDATE) < 9000
|
||||
AND wr.WIRDATE >= @f AND wr.WIRDATE < @t AND wr.EQ_ <> 0)
|
||||
SELECT w.WIRDATE, CAST(ISNULL(w.EQ_,0) AS float), w.D_REST, w.K_REST,
|
||||
CAST(ISNULL(w.D_SUMMA,0) AS float), CAST(ISNULL(w.K_SUMMA,0) AS float), ISNULL(sv.ISIN,'')
|
||||
FROM w
|
||||
LEFT JOIN OD_RESTS sr ON sr.ID = w.sec_rest
|
||||
LEFT JOIN OD_VALUES sv ON sv.ID = sr.REG_2`, in), sql.Named("f", from), sql.Named("t", to))
|
||||
wrows, err := conn.QueryContext(ctx, fmt.Sprintf(fsql.Arch10, in), sql.Named("f", from), sql.Named("t", to))
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user