Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send image urls #956

Merged
merged 78 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
251a613
test banding images (rough code sketch)
TylerNoblett Oct 17, 2023
e08b7ea
add log
TylerNoblett Oct 18, 2023
c5667a4
add fe log for testing
TylerNoblett Oct 18, 2023
41c74e6
send xkcd comic instead of url (since it's not working properly)
TylerNoblett Oct 18, 2023
f87300e
add logs
TylerNoblett Oct 18, 2023
a387abf
add content store name log
TylerNoblett Oct 18, 2023
1332c97
change logic to directly check CS name
TylerNoblett Oct 18, 2023
a0ee136
add log to ensure prodstore works
TylerNoblett Oct 18, 2023
2be8388
fix prod store
TylerNoblett Oct 19, 2023
3b95753
check via name rather than type
TylerNoblett Oct 19, 2023
a2fd940
ensure s3 logic goes through
TylerNoblett Oct 19, 2023
e90adac
check for correct STore type
TylerNoblett Oct 19, 2023
bb7ede9
remove xkcd comic as dummy string
TylerNoblett Oct 19, 2023
91cc18b
add a few TODOS
TylerNoblett Oct 19, 2023
6ae0040
create correct Type for url
TylerNoblett Oct 19, 2023
b336e3c
s3 and other images work now
TylerNoblett Oct 19, 2023
5f473b4
add logs for testing
TylerNoblett Oct 19, 2023
776394b
cleanup small things
TylerNoblett Oct 19, 2023
7d59168
send string instead of object
TylerNoblett Oct 19, 2023
0da61d6
fix non-img media
TylerNoblett Oct 19, 2023
90779f8
add log to check s3 results
TylerNoblett Oct 20, 2023
0303a29
add another log
TylerNoblett Oct 20, 2023
9c692d4
see if url exists
TylerNoblett Oct 20, 2023
d220065
add additoinal logging
TylerNoblett Oct 20, 2023
11f157e
check to see if reader is working
TylerNoblett Oct 20, 2023
279f9f2
put in demo image if
TylerNoblett Oct 20, 2023
f23a75e
remove logging for reader
TylerNoblett Oct 20, 2023
c5149df
ensure only images are sent out of band
TylerNoblett Oct 20, 2023
631e535
change reader to be io.Reader
TylerNoblett Oct 20, 2023
353212b
send evidence preview to determine issue
TylerNoblett Oct 20, 2023
bc11d9b
change logs to prevent failure?
TylerNoblett Oct 20, 2023
5d1dd4c
remove other logic to ensure reponse works
TylerNoblett Oct 20, 2023
0ca09ed
use exact same logic
TylerNoblett Oct 20, 2023
48f9344
test using terminal reader to see what values are
TylerNoblett Oct 20, 2023
eabc4f0
clean up / new logs
TylerNoblett Oct 20, 2023
b7152d4
create separate endpoint
TylerNoblett Oct 20, 2023
2b4f671
Revert "create separate endpoint"
TylerNoblett Oct 20, 2023
8634559
make sure I'm not emptying the buffer
TylerNoblett Oct 20, 2023
4fbaff8
try new reader method
TylerNoblett Oct 20, 2023
54004e7
try longer buffer
TylerNoblett Oct 20, 2023
9d69959
set length to be lenght of url
TylerNoblett Oct 20, 2023
99e976a
add log to see how long url is
TylerNoblett Oct 20, 2023
9f4b7e2
try to get it working again
TylerNoblett Oct 20, 2023
f31fc15
use simpler reader
TylerNoblett Oct 20, 2023
60f71c7
try ReadAll
TylerNoblett Oct 23, 2023
e7c9ca2
try generic read with loop
TylerNoblett Oct 23, 2023
08b2817
create url endpoint
TylerNoblett Oct 23, 2023
ac5fd08
add some logs
TylerNoblett Oct 23, 2023
123d771
add additional logging
TylerNoblett Oct 23, 2023
0381bd1
correct url type
TylerNoblett Oct 23, 2023
3f1dc21
add content type
TylerNoblett Oct 23, 2023
c750b41
add log to see specific url
TylerNoblett Oct 23, 2023
9ae192b
relog url
TylerNoblett Oct 23, 2023
3c9ffd9
add additonal logs
TylerNoblett Oct 23, 2023
e2d01ca
check type
TylerNoblett Oct 23, 2023
1648b5c
parse json
TylerNoblett Oct 23, 2023
35412fe
parse further down
TylerNoblett Oct 23, 2023
5840575
fix json error message
TylerNoblett Oct 23, 2023
dfa54b1
follow dto conventions
TylerNoblett Oct 23, 2023
96404ba
TODO cleanup
TylerNoblett Oct 23, 2023
7deb1dd
additional cleanup
TylerNoblett Oct 23, 2023
5b60956
add back content headers
TylerNoblett Oct 24, 2023
7da9dab
try another reader method
TylerNoblett Oct 24, 2023
84c8f2b
only send url stream for images
TylerNoblett Oct 24, 2023
5b8d7d6
add logs
TylerNoblett Oct 24, 2023
106aa97
clean up extraneous endpoint
TylerNoblett Oct 24, 2023
5eb29ac
correct boolean
TylerNoblett Oct 24, 2023
f364e01
add logs
TylerNoblett Oct 24, 2023
8b9c027
remove logs
TylerNoblett Oct 24, 2023
bc6d1c1
remove TODO
TylerNoblett Oct 24, 2023
04881c1
ensure only images get sendUrl
TylerNoblett Oct 24, 2023
3f2188c
revert index page
TylerNoblett Oct 24, 2023
bbe1f8c
fix spacing
TylerNoblett Oct 24, 2023
2176437
fix spacing agian
TylerNoblett Oct 24, 2023
1071b00
revert accidental changes
TylerNoblett Oct 24, 2023
9f26bed
fix spacing
TylerNoblett Oct 24, 2023
bc891d1
add lazy load component
TylerNoblett Oct 27, 2023
ebc98b0
lowering s3 url validity to 30 minutes
jkennedyvz Nov 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions backend/contentstore/s3store.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package contentstore

import (
"io"
"time"

"github.com/ashirt-ops/ashirt-server/backend"
"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -70,6 +71,22 @@ func (s *S3Store) Read(key string) (io.Reader, error) {
return res.Body, nil
}

func (s *S3Store) SendURL(key string) (*string, error) {
contentType := "image/jpeg"
req, _ := s.s3Client.GetObjectRequest(&s3.GetObjectInput{
Bucket: aws.String(s.bucketName),
Key: aws.String(key),
ResponseContentType: aws.String(contentType),
})

url, err := req.Presign(time.Hour * 8)
if err != nil {
return nil, backend.WrapError("Unable to get presigned URL", err)
}

return &url, nil
}

// Delete removes files in in your OS's temp directory
func (s *S3Store) Delete(key string) error {
_, err := s.s3Client.DeleteObject(&s3.DeleteObjectInput{
Expand Down
1 change: 1 addition & 0 deletions backend/dtos/dtos.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Evidence struct {
Operator User `json:"operator"`
Tags []Tag `json:"tags"`
ContentType string `json:"contentType"`
SendUrl bool `json:"sendUrl"`
}

type EvidenceMetadata struct {
Expand Down
11 changes: 9 additions & 2 deletions backend/server/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package server

import (
"bytes"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -479,7 +480,7 @@ func bindWebRoutes(r chi.Router, db *database.Connection, contentStore contentst
if dr.Error != nil {
return nil, dr.Error
}
return services.ListEvidenceForOperation(r.Context(), db, i)
return services.ListEvidenceForOperation(r.Context(), db, contentStore, i)
}))

route(r, "GET", "/operations/{operation_slug}/evidence/creators", jsonHandler(func(r *http.Request) (interface{}, error) {
Expand Down Expand Up @@ -519,7 +520,13 @@ func bindWebRoutes(r chi.Router, db *database.Connection, contentStore contentst
if err != nil {
return nil, backend.WrapError("Unable to read evidence", err)
}

if s3Store, ok := contentStore.(*contentstore.S3Store); ok && evidence.ContentType == "image" {
url, err := services.SendUrl(r.Context(), db, s3Store, i)
if err != nil {
return nil, backend.WrapError("Unable get s3 URL", err)
}
return bytes.NewReader([]byte(*url)), nil
}
if i.LoadPreview {
return evidence.Preview, nil
}
Expand Down
25 changes: 24 additions & 1 deletion backend/services/evidence.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ func ListEvidenceForFinding(ctx context.Context, db *database.Connection, i List

// ListEvidenceForOperation retrieves all evidence for a particular operation id matching a particular
// set of filters (e.g. tag:some_tag)
func ListEvidenceForOperation(ctx context.Context, db *database.Connection, i ListEvidenceForOperationInput) ([]*dtos.Evidence, error) {
func ListEvidenceForOperation(ctx context.Context, db *database.Connection, contentStore contentstore.Store, i ListEvidenceForOperationInput) ([]*dtos.Evidence, error) {
operation, err := lookupOperation(db, i.OperationSlug)
if err != nil {
return nil, backend.WrapError("Unable to list evidence for an operation", backend.UnauthorizedReadErr(err))
Expand Down Expand Up @@ -316,6 +316,12 @@ func ListEvidenceForOperation(ctx context.Context, db *database.Connection, i Li
}

evidenceDTO := make([]*dtos.Evidence, len(evidence))

sendUrl := false
if _, ok := contentStore.(*contentstore.S3Store); ok {
sendUrl = true
}

for idx, evi := range evidence {
tags, ok := tagsByEvidenceID[evi.ID]

Expand All @@ -330,11 +336,28 @@ func ListEvidenceForOperation(ctx context.Context, db *database.Connection, i Li
OccurredAt: evi.OccurredAt,
ContentType: evi.ContentType,
Tags: tags,
SendUrl: sendUrl,
}
}
return evidenceDTO, nil
}

func SendUrl(ctx context.Context, db *database.Connection, contentStore *contentstore.S3Store, i ReadEvidenceInput) (*string, error) {
operation, evidence, err := lookupOperationEvidence(db, i.OperationSlug, i.EvidenceUUID)
if err != nil {
return nil, backend.WrapError("Unable to read evidence", backend.UnauthorizedReadErr(err))
}
if err := policy.Require(middleware.Policy(ctx), policy.CanReadOperation{OperationID: operation.ID}); err != nil {
return nil, backend.WrapError("Unwilling to read evidence", backend.UnauthorizedReadErr(err))
}
str, err := contentStore.SendURL(evidence.FullImageKey)
if err != nil {
return nil, backend.WrapError("Unable to get image URL", backend.ServerErr(err))
}

return str, nil

}
func ReadEvidence(ctx context.Context, db *database.Connection, contentStore contentstore.Store, i ReadEvidenceInput) (*ReadEvidenceOutput, error) {
operation, evidence, err := lookupOperationEvidence(db, i.OperationSlug, i.EvidenceUUID)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion backend/services/evidence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ func TestListEvidenceForFinding(t *testing.T) {
func TestListEvidenceForOperation(t *testing.T) {
RunResettableDBTest(t, func(db *database.Connection, _ TestSeedData) {
ctx := contextForUser(UserRon, db)
cs, _ := contentstore.NewMemStore()

masterOp := OpChamberOfSecrets
allEvidence := getFullEvidenceByOperationID(t, db, masterOp.ID)
Expand All @@ -206,7 +207,7 @@ func TestListEvidenceForOperation(t *testing.T) {
Filters: helpers.TimelineFilters{},
}

foundEvidence, err := services.ListEvidenceForOperation(ctx, db, input)
foundEvidence, err := services.ListEvidenceForOperation(ctx, db, cs, input)
require.NoError(t, err)
require.Equal(t, len(foundEvidence), len(allEvidence))
validateEvidenceSets(t, toRealEvidenceList(foundEvidence), allEvidence, validateEvidence)
Expand Down
2 changes: 1 addition & 1 deletion frontend/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ server {
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; sandbox allow-downloads allow-scripts allow-same-origin allow-forms allow-popups; connect-src 'self'; font-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; report-uri 'https://csp.yahoo.com/beacon/csp?src=ashirt'" always;

add_header Strict-transport-security "max-age=31536000" always;
add_header Expect-CT "max-age=31536000, report-uri='https://csp.yahoo.com/beacon/csp?src=ashirt'" always;

Expand Down
17 changes: 8 additions & 9 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<!doctype html>
<!DOCTYPE html>
<html>
<head>
<title>ASHIRT</title>
<link rel="stylesheet" href="/assets/main.css">
</head>
<body>
<script src="/assets/main.js"></script>
</body>
</html>
<head>
<meta charset="utf-8">
<title>ASHIRT</title>
<meta name="viewport" content="width=device-width, initial-scale=1"><script defer src="/assets/main-c568069d04dd91a55502.js"></script><link href="/assets/main-b0ad39be34ceaa80dd41.css" rel="stylesheet"></head>
<body>
</body>
</html>
2 changes: 2 additions & 0 deletions frontend/src/components/evidence_chooser/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const EvidenceRow = (props: {
evidenceUuid={props.evidence.uuid}
contentType={props.evidence.contentType}
onClick={(e) => { e.stopPropagation(); setLightboxOpen(true)} }
useS3Url={props.evidence.sendUrl}
fitToContainer
viewHint="small"
interactionHint="inactive"
Expand All @@ -55,6 +56,7 @@ const EvidenceRow = (props: {
operationSlug={props.operationSlug}
evidenceUuid={props.evidence.uuid}
contentType={props.evidence.contentType}
useS3Url={props.evidence.sendUrl}
viewHint="large"
interactionHint="active"
/>
Expand Down
14 changes: 12 additions & 2 deletions frontend/src/components/evidence_preview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default (props: {
interactionHint?: InteractionHint,
className?: string,
fitToContainer?: boolean,
useS3Url: boolean,
onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void,
}) => {
const Component = getComponent(props.contentType)
Expand All @@ -65,6 +66,7 @@ type EvidenceProps = {
evidenceUuid: string,
viewHint?: EvidenceViewHint,
interactionHint?: InteractionHint,
useS3Url: boolean
}

const EvidenceCodeblock = (props: EvidenceProps) => {
Expand All @@ -77,8 +79,16 @@ const EvidenceCodeblock = (props: EvidenceProps) => {
}

const EvidenceImage = (props: EvidenceProps) => {
const fullUrl = `/web/operations/${props.operationSlug}/evidence/${props.evidenceUuid}/media`
return <img src={fullUrl} />
if (props.useS3Url) {
const wiredUrl = useWiredData<string>(React.useCallback(() => getEvidenceAsString({
operationSlug: props.operationSlug,
evidenceUuid: props.evidenceUuid,
}), [props.operationSlug, props.evidenceUuid]))
return wiredUrl.render(url => <img src={url} />)
} else {
const fullUrl = `/web/operations/${props.operationSlug}/evidence/${props.evidenceUuid}/media`
return <img src={fullUrl} />
}
}

const EvidenceEvent = (_props: EvidenceProps) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ const uuidToBasicEvidence = (uuid: string): Evidence => ({
occurredAt: new Date(),
tags: [],
contentType: 'none',
sendUrl: false
})

const ChooseEvidenceModal = (props: {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/timeline/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export default (props: {
operationSlug={props.operationSlug}
evidenceUuid={activeEvidence.uuid}
contentType={activeEvidence.contentType}
useS3Url={activeEvidence.sendUrl}
viewHint="large"
interactionHint="active"
/>
Expand Down Expand Up @@ -158,6 +159,7 @@ const TimelineRow = (props: {
operationSlug={props.operationSlug}
evidenceUuid={props.evidence.uuid}
contentType={props.evidence.contentType}
useS3Url={props.evidence.sendUrl}
viewHint="medium"
interactionHint="inactive"
/>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/global_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export type Evidence = {
occurredAt: Date,
tags: Array<Tag>,
contentType: SupportedEvidenceType
sendUrl: boolean,
}

export type ExportedEvidence = Omit<Evidence, 'tags' | 'uuid'> & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export const BatchRunWorker = (props: {
occurredAt: new Date(),
tags: [],
metadata: [],
contentType: 'image'
contentType: 'image',
sendUrl: false
}))
)}
{...modalProps}
Expand Down
5 changes: 3 additions & 2 deletions frontend/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,15 @@ module.exports = (env, argv) => ({
"base-uri 'none'",
"form-action 'none'",
"frame-ancestors 'none'",
"sandbox allow-scripts allow-same-origin allow-forms allow-popups allow-downloads",
"sandbox allow-downloads allow-scripts allow-same-origin allow-forms allow-popups",

// Allow xhr/fonts/images/scripts/css from self
"connect-src 'self'",
"font-src 'self'",
// amazonaws. or buvcket name
"img-src 'self' data:",
"script-src 'self'",
"style-src 'self' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
].join(';'),
},
}
Expand Down