mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-07-06 20:37:54 +02:00
render page can use template variables. Added panic debug info
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
This commit is contained in:
+117
-17
@@ -12,6 +12,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
textTmpl "text/template"
|
||||
"time"
|
||||
@@ -336,6 +337,10 @@ func (s *Server) Handler(c *gin.Context) {
|
||||
"panic", r,
|
||||
"host", c.Request.Host,
|
||||
"url", c.Request.URL.String(),
|
||||
"method", c.Request.Method,
|
||||
"userAgent", c.Request.UserAgent(),
|
||||
"remoteAddr", c.Request.RemoteAddr,
|
||||
"stack", string(debug.Stack()),
|
||||
)
|
||||
c.Status(http.StatusInternalServerError)
|
||||
c.Abort()
|
||||
@@ -1450,31 +1455,126 @@ func (s *Server) renderDenyPage(
|
||||
&repository.PageOption{},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get landing page: %s", err)
|
||||
return fmt.Errorf("failed to get deny page: %s", err)
|
||||
}
|
||||
tmpl, err := textTmpl.New("page").
|
||||
Funcs(service.TemplateFuncs()).
|
||||
Parse(page.Content.MustGet().String())
|
||||
|
||||
// get campaign recipient - there MUST be one if we're rendering a deny page
|
||||
campaignRecipient, _, err := server.GetCampaignRecipientFromURLParams(
|
||||
ctx,
|
||||
c.Request,
|
||||
s.repositories.Identifier,
|
||||
s.repositories.CampaignRecipient,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse page template: %s", err)
|
||||
return fmt.Errorf("failed to get campaign recipient for deny page: %s", err)
|
||||
}
|
||||
baseURL := "https://" + domain.Name
|
||||
w := bytes.NewBuffer([]byte{})
|
||||
err = tmpl.Execute(w,
|
||||
map[string]string{
|
||||
"BaseURL": baseURL,
|
||||
})
|
||||
if campaignRecipient == nil {
|
||||
return fmt.Errorf("campaign recipient is nil")
|
||||
}
|
||||
|
||||
// get recipient ID from campaign recipient with nil check
|
||||
recipientID, err := campaignRecipient.RecipientID.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute page template: %s", err)
|
||||
return fmt.Errorf("campaign recipient has no recipient ID: %s", err)
|
||||
}
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", w.Bytes())
|
||||
recipient, err := s.repositories.Recipient.GetByID(ctx, &recipientID, &repository.RecipientOption{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get recipient: %s", err)
|
||||
}
|
||||
if recipient == nil {
|
||||
return fmt.Errorf("recipient is nil")
|
||||
}
|
||||
|
||||
// get campaign with nil check
|
||||
campaignID, err := campaignRecipient.CampaignID.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("campaign recipient has no campaign ID: %s", err)
|
||||
}
|
||||
campaign, err := s.repositories.Campaign.GetByID(ctx, &campaignID, &repository.CampaignOption{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get campaign: %s", err)
|
||||
}
|
||||
if campaign == nil {
|
||||
return fmt.Errorf("campaign is nil")
|
||||
}
|
||||
|
||||
// get campaign template with email and nil check
|
||||
templateID, err := campaign.TemplateID.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("campaign has no template ID: %s", err)
|
||||
}
|
||||
cTemplate, err := s.repositories.CampaignTemplate.GetByID(
|
||||
ctx,
|
||||
&templateID,
|
||||
&repository.CampaignTemplateOption{
|
||||
WithEmail: true,
|
||||
WithIdentifier: true,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get campaign template: %s", err)
|
||||
}
|
||||
if cTemplate == nil {
|
||||
return fmt.Errorf("campaign template is nil")
|
||||
}
|
||||
|
||||
// get email with nil check
|
||||
emailID, err := cTemplate.EmailID.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("campaign template has no email ID: %s", err)
|
||||
}
|
||||
email, err := s.repositories.Email.GetByID(ctx, &emailID, &repository.EmailOption{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get email: %s", err)
|
||||
}
|
||||
if email == nil {
|
||||
return fmt.Errorf("email is nil")
|
||||
}
|
||||
|
||||
// get campaign recipient ID with nil check
|
||||
campaignRecipientID, err := campaignRecipient.ID.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("campaign recipient has no ID: %s", err)
|
||||
}
|
||||
|
||||
// render with full template context
|
||||
buf, err := s.services.Template.CreatePhishingPageWithCampaign(
|
||||
domain,
|
||||
email,
|
||||
&campaignRecipientID,
|
||||
recipient,
|
||||
page.Content.MustGet().String(),
|
||||
cTemplate,
|
||||
"", // no state parameter for deny pages
|
||||
c.Request.URL.Path,
|
||||
campaign,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to render deny page template: %s", err)
|
||||
}
|
||||
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", buf.Bytes())
|
||||
c.Abort()
|
||||
s.logger.Debugw("rendered deny page: %s",
|
||||
"pageName", page.Name.MustGet().String(),
|
||||
"pageID", page.ID.MustGet().String(),
|
||||
// safely log with nil checks
|
||||
pageName := "unknown"
|
||||
if pageNameVal, err := page.Name.Get(); err == nil {
|
||||
pageName = pageNameVal.String()
|
||||
}
|
||||
pageIDStr := "unknown"
|
||||
if pageIDVal, err := page.ID.Get(); err == nil {
|
||||
pageIDStr = pageIDVal.String()
|
||||
}
|
||||
recipientEmailStr := "unknown"
|
||||
if recipientEmailVal, err := recipient.Email.Get(); err == nil {
|
||||
recipientEmailStr = recipientEmailVal.String()
|
||||
}
|
||||
|
||||
s.logger.Debugw("rendered deny page",
|
||||
"pageName", pageName,
|
||||
"pageID", pageIDStr,
|
||||
"recipientEmail", recipientEmailStr,
|
||||
)
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// AssignRoutes assigns the routes to the server
|
||||
|
||||
+115
-7
@@ -14,6 +14,7 @@ import (
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -159,7 +160,24 @@ func NewProxyHandler(
|
||||
}
|
||||
|
||||
// HandleHTTPRequest processes incoming http requests through the proxy
|
||||
func (m *ProxyHandler) HandleHTTPRequest(w http.ResponseWriter, req *http.Request, domain *database.Domain) error {
|
||||
func (m *ProxyHandler) HandleHTTPRequest(w http.ResponseWriter, req *http.Request, domain *database.Domain) (err error) {
|
||||
// add panic recovery with debug trace
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
m.logger.Errorw("proxy handler panic recovered",
|
||||
"panic", r,
|
||||
"host", req.Host,
|
||||
"path", req.URL.Path,
|
||||
"query", req.URL.RawQuery,
|
||||
"method", req.Method,
|
||||
"userAgent", req.UserAgent(),
|
||||
"remoteAddr", req.RemoteAddr,
|
||||
"stack", string(debug.Stack()),
|
||||
)
|
||||
err = fmt.Errorf("proxy handler panic: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
ctx := req.Context()
|
||||
|
||||
// initialize request context
|
||||
@@ -3140,28 +3158,118 @@ func (m *ProxyHandler) serveDenyPageResponseDirect(req *http.Request, reqCtx *Re
|
||||
return nil
|
||||
}
|
||||
|
||||
// render the deny page
|
||||
htmlContent, err := denyPage.Content.Get()
|
||||
// render deny page with full template processing
|
||||
htmlContent, err := m.renderDenyPageTemplate(req, reqCtx, denyPage, campaign, cTemplate)
|
||||
if err != nil {
|
||||
m.logger.Errorw("failed to render deny page template", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
content := htmlContent.String()
|
||||
|
||||
// create HTTP response
|
||||
resp := &http.Response{
|
||||
StatusCode: 200,
|
||||
Header: make(http.Header),
|
||||
Body: io.NopCloser(strings.NewReader(content)),
|
||||
Body: io.NopCloser(strings.NewReader(htmlContent)),
|
||||
}
|
||||
|
||||
resp.Header.Set("Content-Type", "text/html; charset=utf-8")
|
||||
resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(content)))
|
||||
resp.Header.Set("Content-Length", fmt.Sprintf("%d", len(htmlContent)))
|
||||
resp.Header.Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
// renderDenyPageTemplate renders the deny page with full template processing like evasion pages
|
||||
func (m *ProxyHandler) renderDenyPageTemplate(req *http.Request, reqCtx *RequestContext, page *model.Page, campaign *model.Campaign, cTemplate *model.CampaignTemplate) (string, error) {
|
||||
// get recipient
|
||||
ctx := req.Context()
|
||||
cRecipient, err := m.CampaignRecipientRepository.GetByID(ctx, reqCtx.CampaignRecipientID, &repository.CampaignRecipientOption{})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get campaign recipient: %w", err)
|
||||
}
|
||||
recipientID, err := cRecipient.RecipientID.Get()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get recipient ID: %w", err)
|
||||
}
|
||||
|
||||
// get recipient details
|
||||
recipientRepo := repository.Recipient{DB: m.CampaignRecipientRepository.DB}
|
||||
recipient, err := recipientRepo.GetByID(ctx, &recipientID, &repository.RecipientOption{})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get recipient: %w", err)
|
||||
}
|
||||
|
||||
// get email for template
|
||||
templateID, err := campaign.TemplateID.Get()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get template ID: %w", err)
|
||||
}
|
||||
|
||||
cTemplateWithEmail, err := m.CampaignTemplateRepository.GetByID(ctx, &templateID, &repository.CampaignTemplateOption{
|
||||
WithEmail: true,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get campaign template with email: %w", err)
|
||||
}
|
||||
|
||||
emailID := cTemplateWithEmail.EmailID.MustGet()
|
||||
emailRepo := repository.Email{DB: m.CampaignRepository.DB}
|
||||
email, err := emailRepo.GetByID(ctx, &emailID, &repository.EmailOption{})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get email: %w", err)
|
||||
}
|
||||
|
||||
// get domain
|
||||
hostVO, err := vo.NewString255(req.Host)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create host VO: %w", err)
|
||||
}
|
||||
domain, err := m.DomainRepository.GetByName(ctx, hostVO, &repository.DomainOption{})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get domain: %w", err)
|
||||
}
|
||||
|
||||
// get page content
|
||||
htmlContent, err := page.Content.Get()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get deny page HTML content: %w", err)
|
||||
}
|
||||
|
||||
// convert model.Domain to database.Domain
|
||||
var proxyID *uuid.UUID
|
||||
if id, err := domain.ProxyID.Get(); err == nil {
|
||||
proxyID = &id
|
||||
}
|
||||
|
||||
dbDomain := &database.Domain{
|
||||
ID: domain.ID.MustGet(),
|
||||
Name: domain.Name.MustGet().String(),
|
||||
Type: domain.Type.MustGet().String(),
|
||||
ProxyID: proxyID,
|
||||
ProxyTargetDomain: domain.ProxyTargetDomain.MustGet().String(),
|
||||
HostWebsite: domain.HostWebsite.MustGet(),
|
||||
RedirectURL: domain.RedirectURL.MustGet().String(),
|
||||
}
|
||||
|
||||
// use template service to render the deny page with full template processing
|
||||
buf, err := m.TemplateService.CreatePhishingPageWithCampaign(
|
||||
dbDomain,
|
||||
email,
|
||||
reqCtx.CampaignRecipientID,
|
||||
recipient,
|
||||
htmlContent.String(),
|
||||
cTemplate,
|
||||
"", // no state parameter for deny pages
|
||||
req.URL.Path,
|
||||
campaign,
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to render deny page template: %w", err)
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func (m *ProxyHandler) renderEvasionPageTemplate(req *http.Request, reqCtx *RequestContext, page *model.Page, campaign *model.Campaign, cTemplate *model.CampaignTemplate, nextPageType string, originalURL string) (string, error) {
|
||||
// get recipient
|
||||
ctx := req.Context()
|
||||
|
||||
Reference in New Issue
Block a user