experimental-user-scripts-support.patch 380 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Thu, 24 Jun 2021 12:33:20 +0000
  3. Subject: Experimental user scripts support preview
  4. needs
  5. add-support-for-ISupportHelpAndFeedback.patch
  6. add-support-for-prefs-addon.patch
  7. ---
  8. chrome/android/BUILD.gn | 5 +
  9. .../chrome/browser/AfterStartupTaskUtils.java | 2 +
  10. .../browser/download/DownloadUtils.java | 7 +
  11. chrome/android/java_sources.gni | 3 +
  12. chrome/browser/BUILD.gn | 5 +
  13. chrome/browser/about_flags.cc | 5 +
  14. .../browser/chrome_content_browser_client.cc | 3 +-
  15. chrome/browser/flag_descriptions.cc | 5 +
  16. chrome/browser/flag_descriptions.h | 3 +
  17. chrome/browser/prefs/browser_prefs.cc | 2 +
  18. chrome/browser/profiles/BUILD.gn | 1 +
  19. ...hrome_browser_main_extra_parts_profiles.cc | 3 +
  20. chrome/browser/profiles/profile_manager.cc | 9 +
  21. chrome/browser/profiles/renderer_updater.cc | 10 +-
  22. chrome/browser/profiles/renderer_updater.h | 1 +
  23. .../webui/chrome_web_ui_controller_factory.cc | 3 +
  24. chrome/chrome_paks.gni | 2 +
  25. chrome/common/renderer_configuration.mojom | 1 +
  26. chrome/renderer/BUILD.gn | 1 +
  27. .../chrome_content_renderer_client.cc | 36 +
  28. .../renderer/chrome_render_thread_observer.cc | 3 +
  29. components/components_strings.grd | 1 +
  30. components/user_scripts/android/BUILD.gn | 82 ++
  31. .../java/res/layout/accept_script_item.xml | 160 ++++
  32. .../java/res/layout/accept_script_list.xml | 10 +
  33. .../java/res/layout/scripts_preference.xml | 40 +
  34. .../android/java/res/values/dimens.xml | 11 +
  35. .../main_preferences_addon_userscripts.xml | 29 +
  36. .../java/res/xml/userscripts_preferences.xml | 34 +
  37. .../user_scripts/UserScriptsUtils.java | 84 ++
  38. .../user_scripts/FragmentWindowAndroid.java | 68 ++
  39. .../user_scripts/IUserScriptsUtils.java | 22 +
  40. .../components/user_scripts/ScriptInfo.java | 37 +
  41. .../user_scripts/ScriptListBaseAdapter.java | 163 ++++
  42. .../user_scripts/ScriptListPreference.java | 171 ++++
  43. .../user_scripts/UserScriptsBridge.java | 178 ++++
  44. .../user_scripts/UserScriptsPreferences.java | 139 +++
  45. .../user_scripts/android/java_sources.gni | 18 +
  46. .../android/user_scripts_bridge.cc | 174 ++++
  47. .../android/user_scripts_bridge.h | 31 +
  48. components/user_scripts/browser/BUILD.gn | 91 ++
  49. .../user_scripts/browser/file_task_runner.cc | 40 +
  50. .../user_scripts/browser/file_task_runner.h | 34 +
  51. .../browser/resources/browser_resources.grd | 14 +
  52. .../browser/resources/user-script-ui/BUILD.gn | 12 +
  53. .../user-script-ui/user-scripts-ui.html | 14 +
  54. .../user-script-ui/user-scripts-ui.js | 9 +
  55. .../browser/ui/user_scripts_ui.cc | 148 ++++
  56. .../user_scripts/browser/ui/user_scripts_ui.h | 39 +
  57. .../browser/user_script_loader.cc | 719 ++++++++++++++++
  58. .../user_scripts/browser/user_script_loader.h | 171 ++++
  59. .../browser/user_script_pref_info.cc | 34 +
  60. .../browser/user_script_pref_info.h | 72 ++
  61. .../user_scripts/browser/user_script_prefs.cc | 276 ++++++
  62. .../user_scripts/browser/user_script_prefs.h | 62 ++
  63. .../browser/userscripts_browser_client.cc | 78 ++
  64. .../browser/userscripts_browser_client.h | 62 ++
  65. components/user_scripts/common/BUILD.gn | 52 ++
  66. components/user_scripts/common/constants.h | 21 +
  67. components/user_scripts/common/error_utils.cc | 54 ++
  68. components/user_scripts/common/error_utils.h | 24 +
  69. .../common/extension_message_generator.cc | 29 +
  70. .../common/extension_message_generator.h | 11 +
  71. .../user_scripts/common/extension_messages.cc | 40 +
  72. .../user_scripts/common/extension_messages.h | 70 ++
  73. components/user_scripts/common/host_id.cc | 31 +
  74. components/user_scripts/common/host_id.h | 35 +
  75. .../user_scripts/common/script_constants.h | 33 +
  76. components/user_scripts/common/url_pattern.cc | 807 ++++++++++++++++++
  77. components/user_scripts/common/url_pattern.h | 301 +++++++
  78. .../user_scripts/common/url_pattern_set.cc | 330 +++++++
  79. .../user_scripts/common/url_pattern_set.h | 161 ++++
  80. components/user_scripts/common/user_script.cc | 317 +++++++
  81. components/user_scripts/common/user_script.h | 403 +++++++++
  82. .../common/user_scripts_features.cc | 32 +
  83. .../common/user_scripts_features.h | 34 +
  84. components/user_scripts/common/view_type.cc | 39 +
  85. components/user_scripts/common/view_type.h | 48 ++
  86. components/user_scripts/renderer/BUILD.gn | 67 ++
  87. .../renderer/extension_frame_helper.cc | 96 +++
  88. .../renderer/extension_frame_helper.h | 92 ++
  89. .../user_scripts/renderer/injection_host.cc | 12 +
  90. .../user_scripts/renderer/injection_host.h | 42 +
  91. .../renderer/resources/greasemonkey_api.js | 82 ++
  92. .../user_scripts_renderer_resources.grd | 14 +
  93. .../user_scripts/renderer/script_context.cc | 213 +++++
  94. .../user_scripts/renderer/script_context.h | 70 ++
  95. .../user_scripts/renderer/script_injection.cc | 342 ++++++++
  96. .../user_scripts/renderer/script_injection.h | 156 ++++
  97. .../renderer/script_injection_callback.cc | 26 +
  98. .../renderer/script_injection_callback.h | 38 +
  99. .../renderer/script_injection_manager.cc | 417 +++++++++
  100. .../renderer/script_injection_manager.h | 102 +++
  101. .../user_scripts/renderer/script_injector.h | 96 +++
  102. .../user_scripts/renderer/scripts_run_info.cc | 31 +
  103. .../user_scripts/renderer/scripts_run_info.h | 70 ++
  104. .../renderer/user_script_injector.cc | 228 +++++
  105. .../renderer/user_script_injector.h | 86 ++
  106. .../user_scripts/renderer/user_script_set.cc | 259 ++++++
  107. .../user_scripts/renderer/user_script_set.h | 102 +++
  108. .../renderer/user_script_set_manager.cc | 77 ++
  109. .../renderer/user_script_set_manager.h | 62 ++
  110. .../renderer/user_scripts_dispatcher.cc | 36 +
  111. .../renderer/user_scripts_dispatcher.h | 48 ++
  112. .../renderer/user_scripts_renderer_client.cc | 105 +++
  113. .../renderer/user_scripts_renderer_client.h | 36 +
  114. .../renderer/web_ui_injection_host.cc | 40 +
  115. .../renderer/web_ui_injection_host.h | 28 +
  116. .../strings/userscripts_strings.grdp | 55 ++
  117. tools/gritsettings/resource_ids.spec | 6 +
  118. 110 files changed, 9441 insertions(+), 2 deletions(-)
  119. create mode 100755 components/user_scripts/android/BUILD.gn
  120. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_item.xml
  121. create mode 100644 components/user_scripts/android/java/res/layout/accept_script_list.xml
  122. create mode 100644 components/user_scripts/android/java/res/layout/scripts_preference.xml
  123. create mode 100755 components/user_scripts/android/java/res/values/dimens.xml
  124. create mode 100755 components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  125. create mode 100644 components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  126. create mode 100755 components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  127. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  128. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  129. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  130. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  131. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  132. create mode 100644 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  133. create mode 100755 components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  134. create mode 100644 components/user_scripts/android/java_sources.gni
  135. create mode 100644 components/user_scripts/android/user_scripts_bridge.cc
  136. create mode 100644 components/user_scripts/android/user_scripts_bridge.h
  137. create mode 100755 components/user_scripts/browser/BUILD.gn
  138. create mode 100755 components/user_scripts/browser/file_task_runner.cc
  139. create mode 100755 components/user_scripts/browser/file_task_runner.h
  140. create mode 100644 components/user_scripts/browser/resources/browser_resources.grd
  141. create mode 100644 components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  142. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  143. create mode 100644 components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  144. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.cc
  145. create mode 100644 components/user_scripts/browser/ui/user_scripts_ui.h
  146. create mode 100755 components/user_scripts/browser/user_script_loader.cc
  147. create mode 100755 components/user_scripts/browser/user_script_loader.h
  148. create mode 100644 components/user_scripts/browser/user_script_pref_info.cc
  149. create mode 100644 components/user_scripts/browser/user_script_pref_info.h
  150. create mode 100644 components/user_scripts/browser/user_script_prefs.cc
  151. create mode 100644 components/user_scripts/browser/user_script_prefs.h
  152. create mode 100755 components/user_scripts/browser/userscripts_browser_client.cc
  153. create mode 100755 components/user_scripts/browser/userscripts_browser_client.h
  154. create mode 100755 components/user_scripts/common/BUILD.gn
  155. create mode 100755 components/user_scripts/common/constants.h
  156. create mode 100755 components/user_scripts/common/error_utils.cc
  157. create mode 100755 components/user_scripts/common/error_utils.h
  158. create mode 100755 components/user_scripts/common/extension_message_generator.cc
  159. create mode 100755 components/user_scripts/common/extension_message_generator.h
  160. create mode 100755 components/user_scripts/common/extension_messages.cc
  161. create mode 100755 components/user_scripts/common/extension_messages.h
  162. create mode 100755 components/user_scripts/common/host_id.cc
  163. create mode 100755 components/user_scripts/common/host_id.h
  164. create mode 100755 components/user_scripts/common/script_constants.h
  165. create mode 100755 components/user_scripts/common/url_pattern.cc
  166. create mode 100755 components/user_scripts/common/url_pattern.h
  167. create mode 100755 components/user_scripts/common/url_pattern_set.cc
  168. create mode 100755 components/user_scripts/common/url_pattern_set.h
  169. create mode 100755 components/user_scripts/common/user_script.cc
  170. create mode 100755 components/user_scripts/common/user_script.h
  171. create mode 100644 components/user_scripts/common/user_scripts_features.cc
  172. create mode 100644 components/user_scripts/common/user_scripts_features.h
  173. create mode 100755 components/user_scripts/common/view_type.cc
  174. create mode 100755 components/user_scripts/common/view_type.h
  175. create mode 100755 components/user_scripts/renderer/BUILD.gn
  176. create mode 100755 components/user_scripts/renderer/extension_frame_helper.cc
  177. create mode 100755 components/user_scripts/renderer/extension_frame_helper.h
  178. create mode 100755 components/user_scripts/renderer/injection_host.cc
  179. create mode 100755 components/user_scripts/renderer/injection_host.h
  180. create mode 100755 components/user_scripts/renderer/resources/greasemonkey_api.js
  181. create mode 100755 components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  182. create mode 100755 components/user_scripts/renderer/script_context.cc
  183. create mode 100755 components/user_scripts/renderer/script_context.h
  184. create mode 100755 components/user_scripts/renderer/script_injection.cc
  185. create mode 100755 components/user_scripts/renderer/script_injection.h
  186. create mode 100755 components/user_scripts/renderer/script_injection_callback.cc
  187. create mode 100755 components/user_scripts/renderer/script_injection_callback.h
  188. create mode 100755 components/user_scripts/renderer/script_injection_manager.cc
  189. create mode 100755 components/user_scripts/renderer/script_injection_manager.h
  190. create mode 100755 components/user_scripts/renderer/script_injector.h
  191. create mode 100755 components/user_scripts/renderer/scripts_run_info.cc
  192. create mode 100755 components/user_scripts/renderer/scripts_run_info.h
  193. create mode 100755 components/user_scripts/renderer/user_script_injector.cc
  194. create mode 100755 components/user_scripts/renderer/user_script_injector.h
  195. create mode 100755 components/user_scripts/renderer/user_script_set.cc
  196. create mode 100755 components/user_scripts/renderer/user_script_set.h
  197. create mode 100755 components/user_scripts/renderer/user_script_set_manager.cc
  198. create mode 100755 components/user_scripts/renderer/user_script_set_manager.h
  199. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.cc
  200. create mode 100755 components/user_scripts/renderer/user_scripts_dispatcher.h
  201. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.cc
  202. create mode 100755 components/user_scripts/renderer/user_scripts_renderer_client.h
  203. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.cc
  204. create mode 100755 components/user_scripts/renderer/web_ui_injection_host.h
  205. create mode 100755 components/user_scripts/strings/userscripts_strings.grdp
  206. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
  207. --- a/chrome/android/BUILD.gn
  208. +++ b/chrome/android/BUILD.gn
  209. @@ -239,6 +239,10 @@ android_resources("chrome_app_java_resources") {
  210. "//third_party/androidx:androidx_preference_preference_java",
  211. "//third_party/androidx:androidx_recyclerview_recyclerview_java",
  212. ]
  213. +
  214. + # this need to be into android_resources("chrome_app_java_resources") section because
  215. + # android:java_resources are packed *_percent.pak and placed in the executable folder
  216. + deps += [ "//components/user_scripts/android:java_resources" ]
  217. }
  218. if (enable_vr) {
  219. @@ -477,6 +481,7 @@ android_library("chrome_java") {
  220. "//components/ukm/android:java",
  221. "//components/url_formatter/android:url_formatter_java",
  222. "//components/user_prefs/android:java",
  223. + "//components/user_scripts/android:java",
  224. "//components/variations/android:variations_java",
  225. "//components/version_info/android:version_constants_java",
  226. "//components/viz/common:common_java",
  227. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java
  228. --- a/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java
  229. +++ b/chrome/android/java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java
  230. @@ -4,6 +4,7 @@
  231. package org.chromium.chrome.browser;
  232. import org.chromium.base.annotations.NativeMethods;
  233. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  234. /**
  235. * JNI call glue for AfterStartupTaskUtils in C++.
  236. @@ -17,6 +18,7 @@ public final class AfterStartupTaskUtils {
  237. * to run and newly posted tasks will no longer be deferred.
  238. */
  239. public static void setStartupComplete() {
  240. + UserScriptsUtils.Initialize();
  241. AfterStartupTaskUtilsJni.get().setStartupComplete();
  242. }
  243. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  244. --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  245. +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
  246. @@ -62,6 +62,7 @@ import org.chromium.content_public.browser.BrowserStartupController;
  247. import org.chromium.content_public.browser.LoadUrlParams;
  248. import org.chromium.ui.base.DeviceFormFactor;
  249. import org.chromium.ui.widget.Toast;
  250. +import org.chromium.chrome.browser.user_scripts.UserScriptsUtils;
  251. import java.io.File;
  252. @@ -380,6 +381,12 @@ public class DownloadUtils {
  253. Context context = ContextUtils.getApplicationContext();
  254. DownloadManagerService service = DownloadManagerService.getDownloadManagerService();
  255. + if (UserScriptsUtils.getInstance().openFile(filePath, mimeType, downloadGuid,
  256. + originalUrl, referrer,
  257. + getUriForItem(filePath))) {
  258. + return true;
  259. + }
  260. +
  261. // Check if Chrome should open the file itself.
  262. if (service.isDownloadOpenableInBrowser(mimeType)) {
  263. // Share URIs use the content:// scheme when able, which looks bad when displayed
  264. diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
  265. --- a/chrome/android/java_sources.gni
  266. +++ b/chrome/android/java_sources.gni
  267. @@ -20,6 +20,7 @@ import("//components/feed/features.gni")
  268. import("//components/offline_pages/buildflags/features.gni")
  269. import("//components/omnibox/browser/test_java_sources.gni")
  270. import("//device/vr/buildflags/buildflags.gni")
  271. +import("//components/user_scripts/android/java_sources.gni")
  272. chrome_java_sources += public_autofill_assistant_java_sources
  273. @@ -53,3 +54,5 @@ if (enable_arcore) {
  274. "java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java",
  275. ]
  276. }
  277. +
  278. +chrome_java_sources += userscripts_java_sources
  279. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  280. --- a/chrome/browser/BUILD.gn
  281. +++ b/chrome/browser/BUILD.gn
  282. @@ -3345,6 +3345,11 @@ static_library("browser") {
  283. ]
  284. deps += [ "//chrome/android/modules/dev_ui/provider:native" ]
  285. }
  286. + deps += [
  287. + "//components/user_scripts/common",
  288. + "//components/user_scripts/browser",
  289. + "//components/user_scripts/android",
  290. + ]
  291. } else {
  292. #!is_android
  293. sources += [
  294. diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
  295. --- a/chrome/browser/about_flags.cc
  296. +++ b/chrome/browser/about_flags.cc
  297. @@ -138,6 +138,7 @@
  298. #include "components/translate/core/browser/translate_ranker_impl.h"
  299. #include "components/translate/core/common/translate_util.h"
  300. #include "components/ui_devtools/switches.h"
  301. +#include "components/user_scripts/common/user_scripts_features.h"
  302. #include "components/version_info/version_info.h"
  303. #include "components/viz/common/features.h"
  304. #include "components/viz/common/switches.h"
  305. @@ -6479,6 +6480,10 @@ const FeatureEntry kFeatureEntries[] = {
  306. FEATURE_VALUE_TYPE(features::kUserDataSnapshot)},
  307. #endif
  308. + {"enable-userscripts-log", flag_descriptions::kEnableLoggingUserScriptsName,
  309. + flag_descriptions::kEnableLoggingUserScriptsDescription, kOsDesktop | kOsAndroid,
  310. + FEATURE_VALUE_TYPE(user_scripts::features::kEnableLoggingUserScripts)},
  311. +
  312. #if defined(OS_WIN)
  313. {"run-video-capture-service-in-browser",
  314. flag_descriptions::kRunVideoCaptureServiceInBrowserProcessName,
  315. diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
  316. --- a/chrome/browser/chrome_content_browser_client.cc
  317. +++ b/chrome/browser/chrome_content_browser_client.cc
  318. @@ -4603,7 +4603,8 @@ ChromeContentBrowserClient::CreateURLLoaderThrottles(
  319. chrome::mojom::DynamicParams dynamic_params = {
  320. profile->GetPrefs()->GetBoolean(prefs::kForceGoogleSafeSearch),
  321. profile->GetPrefs()->GetInteger(prefs::kForceYouTubeRestrict),
  322. - profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps)};
  323. + profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps),
  324. + false /*-> allow_userscript, don't care */};
  325. result.push_back(std::make_unique<GoogleURLLoaderThrottle>(
  326. #if defined(OS_ANDROID)
  327. client_data_header, night_mode_enabled, is_tab_large_enough,
  328. diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
  329. --- a/chrome/browser/flag_descriptions.cc
  330. +++ b/chrome/browser/flag_descriptions.cc
  331. @@ -5156,6 +5156,11 @@ const char kUserDataSnapshotDescription[] =
  332. "update and restoring them after a version rollback.";
  333. #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
  334. +const char kEnableLoggingUserScriptsName[] = "Enable logging user scripts component";
  335. +const char kEnableLoggingUserScriptsDescription[] =
  336. + "Enables logging for troubleshooting feature. "
  337. + "Enabling logs may make browsing slower.";
  338. +
  339. #if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC)
  340. const char kWebShareName[] = "Web Share";
  341. const char kWebShareDescription[] =
  342. diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
  343. --- a/chrome/browser/flag_descriptions.h
  344. +++ b/chrome/browser/flag_descriptions.h
  345. @@ -3017,6 +3017,9 @@ extern const char kUserDataSnapshotName[];
  346. extern const char kUserDataSnapshotDescription[];
  347. #endif // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
  348. +extern const char kEnableLoggingUserScriptsName[];
  349. +extern const char kEnableLoggingUserScriptsDescription[];
  350. +
  351. #if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC)
  352. extern const char kWebShareName[];
  353. extern const char kWebShareDescription[];
  354. diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
  355. --- a/chrome/browser/prefs/browser_prefs.cc
  356. +++ b/chrome/browser/prefs/browser_prefs.cc
  357. @@ -227,6 +227,7 @@
  358. #include "components/ntp_tiles/popular_sites_impl.h"
  359. #include "components/permissions/contexts/geolocation_permission_context_android.h"
  360. #include "components/query_tiles/tile_service_prefs.h"
  361. +#include "components/user_scripts/browser/user_script_prefs.h"
  362. #else // defined(OS_ANDROID)
  363. #include "chrome/browser/accessibility/caption_controller.h"
  364. #include "chrome/browser/cart/cart_service.h"
  365. @@ -977,6 +978,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
  366. translate::TranslatePrefs::RegisterProfilePrefs(registry);
  367. omnibox::RegisterProfilePrefs(registry);
  368. ZeroSuggestProvider::RegisterProfilePrefs(registry);
  369. + user_scripts::UserScriptsPrefs::RegisterProfilePrefs(registry);
  370. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  371. RegisterSessionServiceLogProfilePrefs(registry);
  372. diff --git a/chrome/browser/profiles/BUILD.gn b/chrome/browser/profiles/BUILD.gn
  373. --- a/chrome/browser/profiles/BUILD.gn
  374. +++ b/chrome/browser/profiles/BUILD.gn
  375. @@ -42,6 +42,7 @@ source_set("profile") {
  376. "//components/pref_registry",
  377. "//components/sync/driver",
  378. "//components/variations",
  379. + "//components/user_scripts/browser",
  380. "//content/public/browser",
  381. "//extensions/buildflags",
  382. ]
  383. diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  384. --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  385. +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
  386. @@ -205,6 +205,8 @@
  387. #include "chrome/browser/ui/cocoa/screentime/screentime_features.h"
  388. #endif
  389. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  390. +
  391. namespace chrome {
  392. void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
  393. @@ -472,6 +474,7 @@ void ChromeBrowserMainExtraPartsProfiles::
  394. #endif
  395. WebDataServiceFactory::GetInstance();
  396. webrtc_event_logging::WebRtcEventLogManagerKeyedServiceFactory::GetInstance();
  397. + user_scripts::UserScriptsBrowserClient::GetInstance();
  398. }
  399. void ChromeBrowserMainExtraPartsProfiles::PreProfileInit() {
  400. diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
  401. --- a/chrome/browser/profiles/profile_manager.cc
  402. +++ b/chrome/browser/profiles/profile_manager.cc
  403. @@ -113,6 +113,8 @@
  404. #include "extensions/common/manifest.h"
  405. #endif
  406. +#include "components/user_scripts/browser/userscripts_browser_client.h"
  407. +
  408. #if BUILDFLAG(ENABLE_SESSION_SERVICE)
  409. #include "chrome/browser/sessions/session_service_factory.h"
  410. #endif
  411. @@ -1517,6 +1519,13 @@ void ProfileManager::DoFinalInitForServices(Profile* profile,
  412. }
  413. #endif
  414. +
  415. + user_scripts::UserScriptsBrowserClient* userscript_client =
  416. + user_scripts::UserScriptsBrowserClient::GetInstance();
  417. + if (userscript_client) {
  418. + userscript_client->SetProfile(profile);
  419. + }
  420. +
  421. #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
  422. // Initialization needs to happen after extension system initialization (for
  423. // extension::ManagementPolicy) and InitProfileUserPrefs (for setting the
  424. diff --git a/chrome/browser/profiles/renderer_updater.cc b/chrome/browser/profiles/renderer_updater.cc
  425. --- a/chrome/browser/profiles/renderer_updater.cc
  426. +++ b/chrome/browser/profiles/renderer_updater.cc
  427. @@ -26,6 +26,8 @@
  428. #include "chrome/browser/ash/login/signin/oauth2_login_manager_factory.h"
  429. #endif
  430. +#include "components/user_scripts/browser/user_script_prefs.h"
  431. +
  432. namespace {
  433. #if BUILDFLAG(ENABLE_EXTENSIONS)
  434. @@ -72,6 +74,7 @@ RendererUpdater::RendererUpdater(Profile* profile)
  435. force_google_safesearch_.Init(prefs::kForceGoogleSafeSearch, pref_service);
  436. force_youtube_restrict_.Init(prefs::kForceYouTubeRestrict, pref_service);
  437. allowed_domains_for_apps_.Init(prefs::kAllowedDomainsForApps, pref_service);
  438. + activate_userscripts_.Init(user_scripts::prefs::kUserScriptsEnabled, pref_service);
  439. pref_change_registrar_.Init(pref_service);
  440. pref_change_registrar_.Add(
  441. @@ -86,6 +89,10 @@ RendererUpdater::RendererUpdater(Profile* profile)
  442. prefs::kAllowedDomainsForApps,
  443. base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  444. base::Unretained(this)));
  445. + pref_change_registrar_.Add(
  446. + user_scripts::prefs::kUserScriptsEnabled,
  447. + base::BindRepeating(&RendererUpdater::UpdateAllRenderers,
  448. + base::Unretained(this)));
  449. }
  450. RendererUpdater::~RendererUpdater() {
  451. @@ -209,5 +216,6 @@ void RendererUpdater::UpdateRenderer(
  452. ->SetConfiguration(chrome::mojom::DynamicParams::New(
  453. force_google_safesearch_.GetValue(),
  454. force_youtube_restrict_.GetValue(),
  455. - allowed_domains_for_apps_.GetValue()));
  456. + allowed_domains_for_apps_.GetValue(),
  457. + activate_userscripts_.GetValue()));
  458. }
  459. diff --git a/chrome/browser/profiles/renderer_updater.h b/chrome/browser/profiles/renderer_updater.h
  460. --- a/chrome/browser/profiles/renderer_updater.h
  461. +++ b/chrome/browser/profiles/renderer_updater.h
  462. @@ -83,6 +83,7 @@ class RendererUpdater : public KeyedService,
  463. // Prefs that we sync to the renderers.
  464. BooleanPrefMember force_google_safesearch_;
  465. + BooleanPrefMember activate_userscripts_;
  466. IntegerPrefMember force_youtube_restrict_;
  467. StringPrefMember allowed_domains_for_apps_;
  468. diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  469. --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  470. +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  471. @@ -83,6 +83,7 @@
  472. #include "components/security_interstitials/content/urls.h"
  473. #include "components/signin/public/base/signin_buildflags.h"
  474. #include "components/site_engagement/content/site_engagement_service.h"
  475. +#include "components/user_scripts/browser/ui/user_scripts_ui.h"
  476. #include "content/public/browser/web_contents.h"
  477. #include "content/public/browser/web_ui.h"
  478. #include "content/public/common/content_client.h"
  479. @@ -606,6 +607,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
  480. return &NewWebUI<UserActionsUI>;
  481. if (url.host_piece() == chrome::kChromeUIVersionHost)
  482. return &NewWebUI<VersionUI>;
  483. + if (url.host_piece() == user_scripts::kChromeUIUserScriptsHost)
  484. + return &NewWebUI<user_scripts::UserScriptsUI>;
  485. #if !defined(OS_ANDROID)
  486. #if !BUILDFLAG(IS_CHROMEOS_ASH)
  487. diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
  488. --- a/chrome/chrome_paks.gni
  489. +++ b/chrome/chrome_paks.gni
  490. @@ -104,6 +104,7 @@ template("chrome_extra_paks") {
  491. "$root_gen_dir/third_party/blink/public/resources/inspector_overlay_resources.pak",
  492. "$root_gen_dir/ui/resources/webui_generated_resources.pak",
  493. "$root_gen_dir/ui/resources/webui_resources.pak",
  494. + "$root_gen_dir/chrome/userscripts_browser_resources.pak",
  495. ]
  496. deps = [
  497. "//base/tracing/protos:chrome_track_event_resources",
  498. @@ -119,6 +120,7 @@ template("chrome_extra_paks") {
  499. "//third_party/blink/public:devtools_inspector_resources",
  500. "//third_party/blink/public:resources",
  501. "//ui/resources",
  502. + "//components/user_scripts/browser:userscripts_browser_resources_grit",
  503. ]
  504. if (defined(invoker.deps)) {
  505. deps += invoker.deps
  506. diff --git a/chrome/common/renderer_configuration.mojom b/chrome/common/renderer_configuration.mojom
  507. --- a/chrome/common/renderer_configuration.mojom
  508. +++ b/chrome/common/renderer_configuration.mojom
  509. @@ -11,6 +11,7 @@ struct DynamicParams {
  510. bool force_safe_search = true;
  511. int32 youtube_restrict = 0;
  512. string allowed_domains_for_apps;
  513. + bool allow_userscript = false;
  514. };
  515. interface ChromeOSListener {
  516. diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
  517. --- a/chrome/renderer/BUILD.gn
  518. +++ b/chrome/renderer/BUILD.gn
  519. @@ -164,6 +164,7 @@ static_library("renderer") {
  520. "//components/contextual_search/content:renderer",
  521. "//components/data_reduction_proxy/core/common",
  522. "//components/dom_distiller/content/renderer",
  523. + "//components/user_scripts/renderer",
  524. "//components/network_hints/renderer",
  525. "//components/no_state_prefetch/common",
  526. "//components/no_state_prefetch/renderer",
  527. diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
  528. --- a/chrome/renderer/chrome_content_renderer_client.cc
  529. +++ b/chrome/renderer/chrome_content_renderer_client.cc
  530. @@ -169,6 +169,8 @@
  531. #include "chrome/renderer/sandbox_status_extension_android.h"
  532. #include "components/continuous_search/renderer/search_result_extractor_impl.h" // nogncheck
  533. #include "components/embedder_support/android/common/url_constants.h"
  534. +#include "components/user_scripts/common/user_scripts_features.h"
  535. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  536. #else
  537. #include "chrome/renderer/cart/commerce_hint_agent.h"
  538. #include "chrome/renderer/media/chrome_speech_recognition_client.h"
  539. @@ -368,6 +370,12 @@ void ChromeContentRendererClient::RenderThreadStarted() {
  540. ChromeExtensionsRendererClient::GetInstance()->RenderThreadStarted();
  541. #endif
  542. + user_scripts::UserScriptsRendererClient* userscript_client =
  543. + user_scripts::UserScriptsRendererClient::GetInstance();
  544. + if (userscript_client) {
  545. + userscript_client->RenderThreadStarted();
  546. + }
  547. +
  548. #if BUILDFLAG(ENABLE_SPELLCHECK)
  549. if (!spellcheck_)
  550. InitSpellCheck();
  551. @@ -498,6 +506,13 @@ void ChromeContentRendererClient::RenderFrameCreated(
  552. render_frame, registry);
  553. #endif
  554. + user_scripts::UserScriptsRendererClient* userscript_client =
  555. + user_scripts::UserScriptsRendererClient::GetInstance();
  556. + if (userscript_client) {
  557. + userscript_client->RenderFrameCreated(
  558. + render_frame, registry);
  559. + }
  560. +
  561. #if BUILDFLAG(ENABLE_PLUGINS)
  562. new PepperHelper(render_frame);
  563. #endif
  564. @@ -1468,7 +1483,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentStart(
  565. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentStart(
  566. render_frame);
  567. // |render_frame| might be dead by now.
  568. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  569. #endif
  570. + user_scripts::UserScriptsRendererClient* userscript_client =
  571. + user_scripts::UserScriptsRendererClient::GetInstance();
  572. + if (userscript_client) {
  573. + userscript_client->RunScriptsAtDocumentStart(
  574. + render_frame);
  575. + }
  576. }
  577. void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  578. @@ -1477,7 +1499,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentEnd(
  579. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentEnd(
  580. render_frame);
  581. // |render_frame| might be dead by now.
  582. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  583. #endif
  584. + user_scripts::UserScriptsRendererClient* userscript_client =
  585. + user_scripts::UserScriptsRendererClient::GetInstance();
  586. + if (userscript_client) {
  587. + userscript_client->RunScriptsAtDocumentEnd(
  588. + render_frame);
  589. + }
  590. }
  591. void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  592. @@ -1486,7 +1515,14 @@ void ChromeContentRendererClient::RunScriptsAtDocumentIdle(
  593. ChromeExtensionsRendererClient::GetInstance()->RunScriptsAtDocumentIdle(
  594. render_frame);
  595. // |render_frame| might be dead by now.
  596. + static_assert(false, "Compiler error: extensions cannot be enabled with user scripts");
  597. #endif
  598. + user_scripts::UserScriptsRendererClient* userscript_client =
  599. + user_scripts::UserScriptsRendererClient::GetInstance();
  600. + if (userscript_client) {
  601. + userscript_client->RunScriptsAtDocumentIdle(
  602. + render_frame);
  603. + }
  604. }
  605. void ChromeContentRendererClient::
  606. diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc
  607. --- a/chrome/renderer/chrome_render_thread_observer.cc
  608. +++ b/chrome/renderer/chrome_render_thread_observer.cc
  609. @@ -58,6 +58,8 @@
  610. #include "third_party/blink/public/web/web_security_policy.h"
  611. #include "third_party/blink/public/web/web_view.h"
  612. +#include "components/user_scripts/renderer/user_scripts_renderer_client.h"
  613. +
  614. #if BUILDFLAG(ENABLE_EXTENSIONS)
  615. #include "chrome/renderer/extensions/extension_localization_peer.h"
  616. #endif
  617. @@ -241,6 +243,7 @@ void ChromeRenderThreadObserver::SetInitialConfiguration(
  618. void ChromeRenderThreadObserver::SetConfiguration(
  619. chrome::mojom::DynamicParamsPtr params) {
  620. *GetDynamicConfigParams() = std::move(*params);
  621. + user_scripts::UserScriptsRendererClient::GetInstance()->ConfigurationUpdated();
  622. }
  623. void ChromeRenderThreadObserver::SetContentSettingRules(
  624. diff --git a/components/components_strings.grd b/components/components_strings.grd
  625. --- a/components/components_strings.grd
  626. +++ b/components/components_strings.grd
  627. @@ -330,6 +330,7 @@
  628. <part file="undo_strings.grdp" />
  629. <part file="version_ui_strings.grdp" />
  630. <part file="webapps_strings.grdp" />
  631. + <part file="user_scripts/strings/userscripts_strings.grdp" />
  632. <if expr="not is_android and not is_ios">
  633. <part file="management_strings.grdp" />
  634. diff --git a/components/user_scripts/android/BUILD.gn b/components/user_scripts/android/BUILD.gn
  635. new file mode 100755
  636. --- /dev/null
  637. +++ b/components/user_scripts/android/BUILD.gn
  638. @@ -0,0 +1,82 @@
  639. +# This file is part of Bromite.
  640. +
  641. +# Bromite is free software: you can redistribute it and/or modify
  642. +# it under the terms of the GNU General Public License as published by
  643. +# the Free Software Foundation, either version 3 of the License, or
  644. +# (at your option) any later version.
  645. +
  646. +# Bromite is distributed in the hope that it will be useful,
  647. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  648. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  649. +# GNU General Public License for more details.
  650. +
  651. +# You should have received a copy of the GNU General Public License
  652. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  653. +
  654. +import("//build/config/android/rules.gni")
  655. +
  656. +generate_jni("user_scripts_jni_headers") {
  657. + sources = [ "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java" ]
  658. +}
  659. +
  660. +android_resources("java_resources") {
  661. + sources = [
  662. + "java/res/xml/main_preferences_addon_userscripts.xml",
  663. + "java/res/xml/userscripts_preferences.xml",
  664. + "java/res/layout/accept_script_item.xml",
  665. + "java/res/layout/accept_script_list.xml",
  666. + "java/res/layout/scripts_preference.xml",
  667. + "java/res/values/dimens.xml"
  668. + ]
  669. +
  670. + deps = [
  671. + "//components/browser_ui/strings/android:browser_ui_strings_grd",
  672. + "//components/browser_ui/styles/android:java_resources",
  673. + "//components/strings:components_strings_grd",
  674. + "//ui/android:ui_java_resources",
  675. + ]
  676. +}
  677. +
  678. +android_library("java") {
  679. + sources = [
  680. + "java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java",
  681. + "java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java",
  682. + "java/src/org/chromium/components/user_scripts/UserScriptsBridge.java",
  683. + "java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java",
  684. + "java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java",
  685. + "java/src/org/chromium/components/user_scripts/ScriptListPreference.java",
  686. + "java/src/org/chromium/components/user_scripts/ScriptInfo.java",
  687. + ]
  688. + deps = [
  689. + ":java_resources",
  690. + "//base:base_java",
  691. + "//base:jni_java",
  692. + "//components/embedder_support/android:browser_context_java",
  693. + "//components/browser_ui/settings/android:java",
  694. + "//components/browser_ui/widget/android:java",
  695. + "//content/public/android:content_java",
  696. + "//components/prefs/android:java",
  697. + "//third_party/android_deps:android_support_v7_appcompat_java",
  698. + "//third_party/androidx:androidx_annotation_annotation_java",
  699. + "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
  700. + "//third_party/androidx:androidx_preference_preference_java",
  701. + "//ui/android:ui_java",
  702. + ]
  703. + resources_package = "org.chromium.components.user_scripts"
  704. + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
  705. +}
  706. +
  707. +source_set("android") {
  708. + sources = [
  709. + "user_scripts_bridge.cc",
  710. + "user_scripts_bridge.h",
  711. + ]
  712. + deps = [
  713. + ":user_scripts_jni_headers",
  714. + "//base",
  715. + "//components/user_scripts/browser",
  716. + "//components/embedder_support/android:browser_context",
  717. + "//components/permissions",
  718. + "//content/public/browser",
  719. + ]
  720. +}
  721. diff --git a/components/user_scripts/android/java/res/layout/accept_script_item.xml b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  722. new file mode 100644
  723. --- /dev/null
  724. +++ b/components/user_scripts/android/java/res/layout/accept_script_item.xml
  725. @@ -0,0 +1,160 @@
  726. +<?xml version="1.0" encoding="utf-8"?>
  727. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  728. + Use of this source code is governed by a BSD-style license that can be
  729. + found in the LICENSE file. -->
  730. +
  731. +<LinearLayout
  732. + xmlns:android="http://schemas.android.com/apk/res/android"
  733. + xmlns:app="http://schemas.android.com/apk/res-auto"
  734. + xmlns:tools="http://schemas.android.com/tools"
  735. + android:layout_width="match_parent"
  736. + android:layout_height="wrap_content"
  737. + android:orientation="vertical"
  738. + android:layout_gravity="center_vertical" >
  739. +
  740. + <LinearLayout
  741. + android:layout_marginStart="0dp"
  742. + android:paddingStart="@dimen/draggable_list_item_padding"
  743. + android:paddingEnd="@dimen/draggable_list_item_padding"
  744. + style="@style/ListItemContainer">
  745. +
  746. + <Switch
  747. + android:id="@+id/switch_widget"
  748. + android:layout_width="wrap_content"
  749. + android:layout_height="wrap_content"
  750. + android:paddingEnd="15dp"
  751. + android:focusable="false"
  752. + android:background="@null" />
  753. +
  754. + <LinearLayout
  755. + android:layout_width="0dp"
  756. + android:layout_height="wrap_content"
  757. + android:layout_weight="1"
  758. + android:orientation="vertical"
  759. + android:layout_gravity="center_vertical" >
  760. +
  761. + <TextView
  762. + android:id="@+id/title"
  763. + android:layout_width="match_parent"
  764. + android:layout_height="wrap_content"
  765. + style="@style/PreferenceTitle" />
  766. +
  767. + <TextView
  768. + android:id="@+id/description"
  769. + android:layout_width="match_parent"
  770. + android:layout_height="wrap_content"
  771. + style="@style/PreferenceSummary" />
  772. +
  773. + <LinearLayout
  774. + android:layout_width="match_parent"
  775. + android:layout_height="wrap_content"
  776. + android:layout_weight="1"
  777. + android:paddingTop="5dp"
  778. + android:layout_gravity="center_vertical" >
  779. +
  780. + <TextView
  781. + android:layout_width="wrap_content"
  782. + android:layout_height="wrap_content"
  783. + android:paddingEnd="5dp"
  784. + style="@style/PreferenceSummary"
  785. + android:text="@string/scripts_item_version"
  786. + android:textStyle="bold" />
  787. +
  788. + <TextView
  789. + android:id="@+id/version"
  790. + android:layout_width="match_parent"
  791. + android:layout_height="wrap_content"
  792. + style="@style/PreferenceSummary" />
  793. +
  794. + </LinearLayout>
  795. +
  796. + <LinearLayout
  797. + android:layout_width="match_parent"
  798. + android:layout_height="wrap_content"
  799. + android:layout_weight="1"
  800. + android:layout_gravity="center_vertical" >
  801. +
  802. + <TextView
  803. + android:layout_width="wrap_content"
  804. + android:layout_height="wrap_content"
  805. + android:paddingEnd="5dp"
  806. + style="@style/PreferenceSummary"
  807. + android:text="@string/scripts_item_filename"
  808. + android:textStyle="bold" />
  809. +
  810. + <TextView
  811. + android:id="@+id/file"
  812. + android:layout_width="match_parent"
  813. + android:layout_height="wrap_content"
  814. + style="@style/PreferenceSummary" />
  815. +
  816. + </LinearLayout>
  817. +
  818. + <LinearLayout
  819. + android:id="@+id/url_container"
  820. + android:layout_width="match_parent"
  821. + android:layout_height="wrap_content"
  822. + android:layout_weight="1"
  823. + android:layout_gravity="center_vertical" >
  824. +
  825. + <TextView
  826. + android:layout_width="wrap_content"
  827. + android:layout_height="wrap_content"
  828. + android:paddingEnd="5dp"
  829. + style="@style/PreferenceSummary"
  830. + android:text="@string/scripts_item_url"
  831. + android:textStyle="bold" />
  832. +
  833. + <TextView
  834. + android:id="@+id/url"
  835. + android:layout_width="match_parent"
  836. + android:layout_height="wrap_content"
  837. + android:autoLink="web"
  838. + android:focusable="true"
  839. + android:linksClickable="true" />
  840. +
  841. + </LinearLayout>
  842. +
  843. + </LinearLayout>
  844. +
  845. + <org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
  846. + android:id="@+id/more"
  847. + android:layout_width="wrap_content"
  848. + android:layout_height="match_parent"
  849. + android:paddingStart="@dimen/default_list_row_padding"
  850. + android:paddingEnd="@dimen/default_list_row_padding"
  851. + android:background="@null"
  852. + android:src="@drawable/ic_more_vert_24dp"
  853. + app:menuMaxWidth="@dimen/pref_scripts_item_popup_width"
  854. + app:tint="@color/default_icon_color_tint_list"
  855. + tools:ignore="ContentDescription" />
  856. +
  857. + </LinearLayout>
  858. +
  859. + <LinearLayout
  860. + android:id="@+id/error_layout"
  861. + android:layout_marginStart="0dp"
  862. + android:paddingStart="@dimen/draggable_list_item_padding"
  863. + android:paddingEnd="2dp"
  864. + android:layout_width="match_parent"
  865. + android:layout_height="wrap_content"
  866. + style="@style/ListItemContainer">
  867. +
  868. + <org.chromium.ui.widget.ChromeImageView
  869. + android:id="@+id/icon"
  870. + android:layout_width="40dp"
  871. + android:layout_height="wrap_content"
  872. + android:paddingEnd="15dp"
  873. + android:adjustViewBounds="true"
  874. + android:importantForAccessibility="no"
  875. + app:srcCompat="@drawable/ic_error_outline_red_24dp"/>
  876. +
  877. + <TextView
  878. + android:id="@+id/error"
  879. + android:layout_width="match_parent"
  880. + android:layout_height="wrap_content"
  881. + android:textColor="#F00"
  882. + style="@style/PreferenceSummary" />
  883. +
  884. + </LinearLayout>
  885. +</LinearLayout>
  886. \ No newline at end of file
  887. diff --git a/components/user_scripts/android/java/res/layout/accept_script_list.xml b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  888. new file mode 100644
  889. --- /dev/null
  890. +++ b/components/user_scripts/android/java/res/layout/accept_script_list.xml
  891. @@ -0,0 +1,10 @@
  892. +<?xml version="1.0" encoding="utf-8"?>
  893. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  894. + Use of this source code is governed by a BSD-style license that can be
  895. + found in the LICENSE file. -->
  896. +
  897. +<androidx.recyclerview.widget.RecyclerView
  898. + xmlns:android="http://schemas.android.com/apk/res/android"
  899. + android:id="@+id/script_list"
  900. + android:layout_width="match_parent"
  901. + android:layout_height="wrap_content" />
  902. \ No newline at end of file
  903. diff --git a/components/user_scripts/android/java/res/layout/scripts_preference.xml b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  904. new file mode 100644
  905. --- /dev/null
  906. +++ b/components/user_scripts/android/java/res/layout/scripts_preference.xml
  907. @@ -0,0 +1,40 @@
  908. +<?xml version="1.0" encoding="utf-8"?>
  909. +<!-- Copyright 2017 The Chromium Authors. All rights reserved.
  910. + Use of this source code is governed by a BSD-style license that can be
  911. + found in the LICENSE file. -->
  912. +
  913. +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  914. + android:id="@+id/accept_scripts_list_container"
  915. + style="@style/PreferenceLayout"
  916. + android:layout_width="match_parent"
  917. + android:layout_height="wrap_content"
  918. + android:paddingStart="0dp"
  919. + android:paddingEnd="0dp"
  920. + android:padding="0dp"
  921. + android:orientation="vertical" >
  922. +
  923. + <TextView
  924. + android:layout_width="match_parent"
  925. + android:layout_height="wrap_content"
  926. + android:padding="@dimen/draggable_list_item_padding"
  927. + android:text="@string/scripts_list_description" />
  928. +
  929. + <FrameLayout
  930. + android:id="@android:id/widget_frame"
  931. + android:layout_width="match_parent"
  932. + android:layout_height="wrap_content" />
  933. +
  934. + <TextView
  935. + android:id="@+id/add_script"
  936. + android:layout_width="match_parent"
  937. + android:layout_height="wrap_content"
  938. + android:background="?attr/selectableItemBackground"
  939. + android:clickable="true"
  940. + android:gravity="center_vertical"
  941. + android:padding="@dimen/draggable_list_item_padding"
  942. + android:paddingStart="@dimen/pref_scripts_add_button_padding"
  943. + android:drawablePadding="@dimen/pref_scripts_add_button_padding"
  944. + android:text="@string/add_script"
  945. + style="@style/PreferenceTitle" />
  946. +
  947. +</LinearLayout>
  948. \ No newline at end of file
  949. diff --git a/components/user_scripts/android/java/res/values/dimens.xml b/components/user_scripts/android/java/res/values/dimens.xml
  950. new file mode 100755
  951. --- /dev/null
  952. +++ b/components/user_scripts/android/java/res/values/dimens.xml
  953. @@ -0,0 +1,11 @@
  954. +<?xml version="1.0" encoding="utf-8"?>
  955. +<!-- Copyright 2014 The Chromium Authors. All rights reserved.
  956. + Use of this source code is governed by a BSD-style license that can be
  957. + found in the LICENSE file. -->
  958. +
  959. +<resources xmlns:tools="http://schemas.android.com/tools">
  960. +
  961. + <dimen name="pref_scripts_add_button_padding">24dp</dimen>
  962. + <dimen name="pref_scripts_item_popup_width">260dp</dimen>
  963. +
  964. +</resources>
  965. diff --git a/components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml b/components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  966. new file mode 100755
  967. --- /dev/null
  968. +++ b/components/user_scripts/android/java/res/xml/main_preferences_addon_userscripts.xml
  969. @@ -0,0 +1,29 @@
  970. +<?xml version="1.0" encoding="utf-8"?>
  971. +<!--
  972. + This file is part of Bromite.
  973. +
  974. + Bromite is free software: you can redistribute it and/or modify
  975. + it under the terms of the GNU General Public License as published by
  976. + the Free Software Foundation, either version 3 of the License, or
  977. + (at your option) any later version.
  978. +
  979. + Bromite is distributed in the hope that it will be useful,
  980. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  981. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  982. + GNU General Public License for more details.
  983. +
  984. + You should have received a copy of the GNU General Public License
  985. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  986. +-->
  987. +
  988. +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
  989. + xmlns:app="http://schemas.android.com/apk/res-auto"
  990. + android:orderingFromXml="false">
  991. +
  992. + <Preference
  993. + android:fragment="org.chromium.components.user_scripts.UserScriptsPreferences"
  994. + android:key="userscripts_settings"
  995. + android:order="20"
  996. + android:title="@string/prefs_userscripts_settings"/>
  997. +
  998. +</PreferenceScreen>
  999. diff --git a/components/user_scripts/android/java/res/xml/userscripts_preferences.xml b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1000. new file mode 100644
  1001. --- /dev/null
  1002. +++ b/components/user_scripts/android/java/res/xml/userscripts_preferences.xml
  1003. @@ -0,0 +1,34 @@
  1004. +<?xml version="1.0" encoding="utf-8"?>
  1005. +<!--
  1006. + This file is part of Bromite.
  1007. +
  1008. + Bromite is free software: you can redistribute it and/or modify
  1009. + it under the terms of the GNU General Public License as published by
  1010. + the Free Software Foundation, either version 3 of the License, or
  1011. + (at your option) any later version.
  1012. +
  1013. + Bromite is distributed in the hope that it will be useful,
  1014. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1015. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1016. + GNU General Public License for more details.
  1017. +
  1018. + You should have received a copy of the GNU General Public License
  1019. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1020. +-->
  1021. +
  1022. +<PreferenceScreen
  1023. + xmlns:android="http://schemas.android.com/apk/res/android"
  1024. + xmlns:app="http://schemas.android.com/apk/res-auto">
  1025. +
  1026. + <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
  1027. + android:key="enabled_switch"
  1028. + android:title="@string/option_userscript_flag"
  1029. + android:summaryOn="@string/option_userscript_flag_on"
  1030. + android:summaryOff="@string/option_userscript_flag_off" />
  1031. +
  1032. + <org.chromium.components.user_scripts.ScriptListPreference
  1033. + android:key="script_list"
  1034. + android:layout="@layout/scripts_preference"
  1035. + android:widgetLayout="@layout/accept_script_list" />
  1036. +
  1037. +</PreferenceScreen>
  1038. diff --git a/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  1039. new file mode 100755
  1040. --- /dev/null
  1041. +++ b/components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java
  1042. @@ -0,0 +1,84 @@
  1043. +/*
  1044. + This file is part of Bromite.
  1045. +
  1046. + Bromite is free software: you can redistribute it and/or modify
  1047. + it under the terms of the GNU General Public License as published by
  1048. + the Free Software Foundation, either version 3 of the License, or
  1049. + (at your option) any later version.
  1050. +
  1051. + Bromite is distributed in the hope that it will be useful,
  1052. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1053. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1054. + GNU General Public License for more details.
  1055. +
  1056. + You should have received a copy of the GNU General Public License
  1057. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1058. +*/
  1059. +
  1060. +package org.chromium.chrome.browser.user_scripts;
  1061. +
  1062. +import android.content.Context;
  1063. +import android.content.Intent;
  1064. +import android.provider.Browser;
  1065. +import android.provider.MediaStore;
  1066. +import android.net.Uri;
  1067. +
  1068. +import org.chromium.base.ContextUtils;
  1069. +import org.chromium.base.ContentUriUtils;
  1070. +import org.chromium.base.IntentUtils;
  1071. +
  1072. +import org.chromium.chrome.browser.IntentHandler;
  1073. +import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
  1074. +import org.chromium.components.browser_ui.settings.SettingsLauncher;
  1075. +
  1076. +import org.chromium.components.user_scripts.UserScriptsPreferences;
  1077. +import org.chromium.components.user_scripts.UserScriptsBridge;
  1078. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1079. +
  1080. +public class UserScriptsUtils implements IUserScriptsUtils
  1081. +{
  1082. + private static UserScriptsUtils instance;
  1083. +
  1084. + private UserScriptsUtils() {}
  1085. +
  1086. + public static void Initialize() {
  1087. + instance = new UserScriptsUtils();
  1088. + UserScriptsBridge.registerUtils(instance);
  1089. + }
  1090. +
  1091. + public static UserScriptsUtils getInstance() {
  1092. + return instance;
  1093. + }
  1094. +
  1095. + public boolean openFile(String filePath, String mimeType, String downloadGuid,
  1096. + String originalUrl, String referrer, Uri contentUri) {
  1097. + if (UserScriptsBridge.isEnabled() == false) return false;
  1098. +
  1099. + Context context = ContextUtils.getApplicationContext();
  1100. +
  1101. + if (ContentUriUtils.isContentUri(filePath))
  1102. + filePath = ContentUriUtils.getDisplayName(contentUri, context,
  1103. + MediaStore.MediaColumns.DISPLAY_NAME);
  1104. +
  1105. + if (filePath.toUpperCase().endsWith(".USER.JS") == false) return false;
  1106. +
  1107. + SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
  1108. + Intent intent = settingsLauncher.createSettingsActivityIntent(
  1109. + context, UserScriptsPreferences.class.getName(),
  1110. + UserScriptsPreferences.createFragmentArgsForInstall(filePath));
  1111. + IntentUtils.safeStartActivity(context, intent);
  1112. +
  1113. + return true;
  1114. + }
  1115. +
  1116. + public void openSourceFile(String scriptKey) {
  1117. + Context context = ContextUtils.getApplicationContext();
  1118. +
  1119. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("chrome://user-scripts/?key=" + scriptKey));
  1120. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1121. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1122. + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  1123. + intent.setPackage(context.getPackageName());
  1124. + IntentHandler.startChromeLauncherActivityForTrustedIntent(intent);
  1125. + }
  1126. +}
  1127. \ No newline at end of file
  1128. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  1129. new file mode 100644
  1130. --- /dev/null
  1131. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/FragmentWindowAndroid.java
  1132. @@ -0,0 +1,68 @@
  1133. +// Copyright 2019 The Chromium Authors. All rights reserved.
  1134. +// Use of this source code is governed by a BSD-style license that can be
  1135. +// found in the LICENSE file.
  1136. +
  1137. +package org.chromium.components.user_scripts;
  1138. +
  1139. +import android.annotation.TargetApi;
  1140. +import android.app.Activity;
  1141. +import android.content.Context;
  1142. +import android.content.Intent;
  1143. +import android.content.IntentSender;
  1144. +import android.os.Build;
  1145. +import android.view.View;
  1146. +
  1147. +import androidx.fragment.app.Fragment;
  1148. +
  1149. +import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
  1150. +import org.chromium.ui.base.ActivityAndroidPermissionDelegate;
  1151. +import org.chromium.ui.base.ImmutableWeakReference;
  1152. +import org.chromium.ui.base.IntentWindowAndroid;
  1153. +
  1154. +import java.lang.ref.WeakReference;
  1155. +
  1156. +/**
  1157. + * Implements intent sending for a fragment based window. This should be created when
  1158. + * onAttach() is called on the fragment, and destroyed when onDetach() is called.
  1159. + */
  1160. +public class FragmentWindowAndroid extends IntentWindowAndroid {
  1161. + private Fragment mFragment;
  1162. +
  1163. + // This WeakReference is purely to avoid gc churn of creating a new WeakReference in
  1164. + // every getActivity call. It is not needed for correctness.
  1165. + private ImmutableWeakReference<Activity> mActivityWeakRefHolder;
  1166. +
  1167. + FragmentWindowAndroid(Context context, Fragment fragment) {
  1168. + super(context);
  1169. + mFragment = fragment;
  1170. +
  1171. + setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));
  1172. + setAndroidPermissionDelegate(new ActivityAndroidPermissionDelegate(getActivity()));
  1173. + }
  1174. +
  1175. + @Override
  1176. + protected final boolean startIntentSenderForResult(IntentSender intentSender, int requestCode) {
  1177. + try {
  1178. + mFragment.startIntentSenderForResult(
  1179. + intentSender, requestCode, new Intent(), 0, 0, 0, null);
  1180. + } catch (IntentSender.SendIntentException e) {
  1181. + return false;
  1182. + }
  1183. + return true;
  1184. + }
  1185. +
  1186. + @Override
  1187. + protected final boolean startActivityForResult(Intent intent, int requestCode) {
  1188. + mFragment.startActivityForResult(intent, requestCode, null);
  1189. + return true;
  1190. + }
  1191. +
  1192. + @Override
  1193. + public final WeakReference<Activity> getActivity() {
  1194. + if (mActivityWeakRefHolder == null
  1195. + || mActivityWeakRefHolder.get() != mFragment.getActivity()) {
  1196. + mActivityWeakRefHolder = new ImmutableWeakReference<>(mFragment.getActivity());
  1197. + }
  1198. + return mActivityWeakRefHolder;
  1199. + }
  1200. +}
  1201. \ No newline at end of file
  1202. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1203. new file mode 100644
  1204. --- /dev/null
  1205. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/IUserScriptsUtils.java
  1206. @@ -0,0 +1,22 @@
  1207. +/*
  1208. + This file is part of Bromite.
  1209. +
  1210. + Bromite is free software: you can redistribute it and/or modify
  1211. + it under the terms of the GNU General Public License as published by
  1212. + the Free Software Foundation, either version 3 of the License, or
  1213. + (at your option) any later version.
  1214. +
  1215. + Bromite is distributed in the hope that it will be useful,
  1216. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1217. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1218. + GNU General Public License for more details.
  1219. +
  1220. + You should have received a copy of the GNU General Public License
  1221. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1222. +*/
  1223. +
  1224. +package org.chromium.components.user_scripts;
  1225. +
  1226. +public interface IUserScriptsUtils {
  1227. + public void openSourceFile(String scriptKey);
  1228. +}
  1229. \ No newline at end of file
  1230. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1231. new file mode 100644
  1232. --- /dev/null
  1233. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptInfo.java
  1234. @@ -0,0 +1,37 @@
  1235. +/*
  1236. + This file is part of Bromite.
  1237. +
  1238. + Bromite is free software: you can redistribute it and/or modify
  1239. + it under the terms of the GNU General Public License as published by
  1240. + the Free Software Foundation, either version 3 of the License, or
  1241. + (at your option) any later version.
  1242. +
  1243. + Bromite is distributed in the hope that it will be useful,
  1244. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1245. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1246. + GNU General Public License for more details.
  1247. +
  1248. + You should have received a copy of the GNU General Public License
  1249. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1250. +*/
  1251. +
  1252. +package org.chromium.components.user_scripts;
  1253. +
  1254. +import java.time.LocalDateTime;
  1255. +
  1256. +public class ScriptInfo {
  1257. + public String Key;
  1258. + public String Name;
  1259. + public String Description;
  1260. + public String Version;
  1261. + public String FilePath;
  1262. + public String UrlSource;
  1263. +
  1264. + public boolean Enabled;
  1265. + public LocalDateTime InstallTime;
  1266. +
  1267. + public String ParserError;
  1268. + public boolean ForceDisabled;
  1269. +
  1270. + public ScriptInfo() {}
  1271. +}
  1272. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1273. new file mode 100644
  1274. --- /dev/null
  1275. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListBaseAdapter.java
  1276. @@ -0,0 +1,163 @@
  1277. +/*
  1278. + This file is part of Bromite.
  1279. +
  1280. + Bromite is free software: you can redistribute it and/or modify
  1281. + it under the terms of the GNU General Public License as published by
  1282. + the Free Software Foundation, either version 3 of the License, or
  1283. + (at your option) any later version.
  1284. +
  1285. + Bromite is distributed in the hope that it will be useful,
  1286. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1287. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1288. + GNU General Public License for more details.
  1289. +
  1290. + You should have received a copy of the GNU General Public License
  1291. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1292. +*/
  1293. +
  1294. +package org.chromium.components.user_scripts;
  1295. +
  1296. +import android.content.Context;
  1297. +import android.view.LayoutInflater;
  1298. +import android.view.MotionEvent;
  1299. +import android.view.View;
  1300. +import android.view.ViewGroup;
  1301. +import android.view.accessibility.AccessibilityManager;
  1302. +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
  1303. +import android.widget.ImageView;
  1304. +import android.widget.TextView;
  1305. +import android.widget.Switch;
  1306. +import android.widget.CompoundButton;
  1307. +import android.widget.LinearLayout;
  1308. +
  1309. +import androidx.annotation.DrawableRes;
  1310. +import androidx.annotation.NonNull;
  1311. +import androidx.core.view.ViewCompat;
  1312. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1313. +
  1314. +import org.chromium.components.browser_ui.widget.dragreorder.DragReorderableListAdapter;
  1315. +import org.chromium.components.browser_ui.widget.dragreorder.DragStateDelegate;
  1316. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
  1317. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
  1318. +import org.chromium.ui.widget.ChromeImageView;
  1319. +
  1320. +import java.util.ArrayList;
  1321. +import java.util.List;
  1322. +
  1323. +public class ScriptListBaseAdapter extends DragReorderableListAdapter<ScriptInfo> {
  1324. +
  1325. + class ItemClickListener {
  1326. + void onScriptOnOff(boolean Enabled) {}
  1327. + void onScriptClicked() {}
  1328. + }
  1329. +
  1330. + static class ScriptInfoRowViewHolder extends ViewHolder {
  1331. + private TextView mTitle;
  1332. + private TextView mDescription;
  1333. + private TextView mVersion;
  1334. + private TextView mFile;
  1335. + private TextView mUrl;
  1336. + private TextView mError;
  1337. + private Switch mSwitch;
  1338. + private ChromeImageView mIcon;
  1339. + private LinearLayout mErrorLayout;
  1340. + private LinearLayout mUrlContainer;
  1341. +
  1342. + private ListMenuButton mMoreButton;
  1343. +
  1344. + private CompoundButton.OnCheckedChangeListener mOnOffListener;
  1345. +
  1346. + ScriptInfoRowViewHolder(View view) {
  1347. + super(view);
  1348. +
  1349. + mSwitch = view.findViewById(R.id.switch_widget);
  1350. + mTitle = view.findViewById(R.id.title);
  1351. + mDescription = view.findViewById(R.id.description);
  1352. + mVersion = view.findViewById(R.id.version);
  1353. + mFile = view.findViewById(R.id.file);
  1354. + mUrl = view.findViewById(R.id.url);
  1355. + mUrlContainer = view.findViewById(R.id.url_container);
  1356. + mError = view.findViewById(R.id.error);
  1357. + mIcon = view.findViewById(R.id.icon);
  1358. + mErrorLayout = view.findViewById(R.id.error_layout);
  1359. +
  1360. + mMoreButton = view.findViewById(R.id.more);
  1361. + }
  1362. +
  1363. + protected void updateScriptInfo(ScriptInfo item) {
  1364. + mSwitch.setOnCheckedChangeListener(null);
  1365. + mSwitch.setChecked(item.Enabled);
  1366. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1367. +
  1368. + mSwitch.setEnabled(true);
  1369. + if (item.ForceDisabled) {
  1370. + mSwitch.setEnabled(false);
  1371. + }
  1372. +
  1373. + mTitle.setText(item.Name);
  1374. + mDescription.setText(item.Description);
  1375. + mVersion.setText(item.Version);
  1376. + mFile.setText(item.Key);
  1377. + mUrl.setText(item.UrlSource);
  1378. + mError.setText(item.ParserError);
  1379. +
  1380. + mUrl.setVisibility(View.VISIBLE);
  1381. + if (item.UrlSource == null || item.UrlSource.isEmpty()) {
  1382. + mUrlContainer.setVisibility(View.GONE);
  1383. + }
  1384. + mErrorLayout.setVisibility(View.VISIBLE);
  1385. + if (item.ParserError == null || item.ParserError.isEmpty()) {
  1386. + mErrorLayout.setVisibility(View.GONE);
  1387. + }
  1388. + }
  1389. +
  1390. + void setMenuButtonDelegate(@NonNull ListMenuButtonDelegate delegate) {
  1391. + mMoreButton.setVisibility(View.VISIBLE);
  1392. + mMoreButton.setDelegate(delegate);
  1393. + // Set item row end padding 0 when MenuButton is visible.
  1394. + ViewCompat.setPaddingRelative(itemView, ViewCompat.getPaddingStart(itemView),
  1395. + itemView.getPaddingTop(), 0, itemView.getPaddingBottom());
  1396. + }
  1397. +
  1398. + void setItemListener(@NonNull ItemClickListener listener) {
  1399. + mOnOffListener = (buttonView, isChecked) -> listener.onScriptOnOff(isChecked);
  1400. + mSwitch.setOnCheckedChangeListener(mOnOffListener);
  1401. + itemView.setOnClickListener(view -> listener.onScriptClicked());
  1402. + }
  1403. + }
  1404. +
  1405. + ScriptListBaseAdapter(Context context) {
  1406. + super(context);
  1407. + }
  1408. +
  1409. + @Override
  1410. + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
  1411. + View row = LayoutInflater.from(viewGroup.getContext())
  1412. + .inflate(R.layout.accept_script_item, viewGroup, false);
  1413. + return new ScriptInfoRowViewHolder(row);
  1414. + }
  1415. +
  1416. + @Override
  1417. + public void onBindViewHolder(ViewHolder viewHolder, int i) {
  1418. + ((ScriptInfoRowViewHolder) viewHolder).updateScriptInfo(mElements.get(i));
  1419. + }
  1420. +
  1421. + void setDisplayedScriptInfo(List<ScriptInfo> values) {
  1422. + mElements = new ArrayList<>(values);
  1423. + notifyDataSetChanged();
  1424. + }
  1425. +
  1426. + @Override
  1427. + protected void setOrder(List<ScriptInfo> order) {
  1428. + }
  1429. +
  1430. + @Override
  1431. + protected boolean isActivelyDraggable(ViewHolder viewHolder) {
  1432. + return isPassivelyDraggable(viewHolder);
  1433. + }
  1434. +
  1435. + @Override
  1436. + protected boolean isPassivelyDraggable(ViewHolder viewHolder) {
  1437. + return viewHolder instanceof ScriptInfoRowViewHolder;
  1438. + }
  1439. +}
  1440. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1441. new file mode 100644
  1442. --- /dev/null
  1443. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/ScriptListPreference.java
  1444. @@ -0,0 +1,171 @@
  1445. +/*
  1446. + This file is part of Bromite.
  1447. +
  1448. + Bromite is free software: you can redistribute it and/or modify
  1449. + it under the terms of the GNU General Public License as published by
  1450. + the Free Software Foundation, either version 3 of the License, or
  1451. + (at your option) any later version.
  1452. +
  1453. + Bromite is distributed in the hope that it will be useful,
  1454. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1455. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1456. + GNU General Public License for more details.
  1457. +
  1458. + You should have received a copy of the GNU General Public License
  1459. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1460. +*/
  1461. +
  1462. +package org.chromium.components.user_scripts;
  1463. +
  1464. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItem;
  1465. +import static org.chromium.components.browser_ui.widget.listmenu.BasicListMenu.buildMenuListItemWithEndIcon;
  1466. +
  1467. +import android.content.Context;
  1468. +import android.content.Intent;
  1469. +import android.provider.Browser;
  1470. +import android.net.Uri;
  1471. +import android.util.AttributeSet;
  1472. +import android.widget.TextView;
  1473. +import android.widget.Toast;
  1474. +
  1475. +import androidx.preference.Preference;
  1476. +import androidx.preference.PreferenceViewHolder;
  1477. +import androidx.recyclerview.widget.DividerItemDecoration;
  1478. +import androidx.recyclerview.widget.LinearLayoutManager;
  1479. +import androidx.recyclerview.widget.RecyclerView;
  1480. +import androidx.recyclerview.widget.RecyclerView.ViewHolder;
  1481. +
  1482. +import org.chromium.ui.base.WindowAndroid;
  1483. +import org.chromium.ui.base.ActivityWindowAndroid;
  1484. +
  1485. +import org.chromium.base.ApplicationStatus;
  1486. +import org.chromium.base.ContextUtils;
  1487. +import org.chromium.components.browser_ui.widget.TintedDrawable;
  1488. +import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
  1489. +import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
  1490. +import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
  1491. +import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
  1492. +
  1493. +import org.chromium.components.user_scripts.ScriptListBaseAdapter;
  1494. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1495. +
  1496. +import java.util.List;
  1497. +
  1498. +public class ScriptListPreference extends Preference {
  1499. + private static class ScriptListAdapter
  1500. + extends ScriptListBaseAdapter {
  1501. + private final Context mContext;
  1502. +
  1503. + ScriptListAdapter(Context context) {
  1504. + super(context);
  1505. + mContext = context;
  1506. + }
  1507. +
  1508. + @Override
  1509. + public void onBindViewHolder(ViewHolder holder, int position) {
  1510. + super.onBindViewHolder(holder, position);
  1511. +
  1512. + final ScriptInfo info = getItemByPosition(position);
  1513. +
  1514. + ModelList menuItems = new ModelList();
  1515. +
  1516. + menuItems.add(buildMenuListItem(R.string.remove, 0, 0, true));
  1517. + menuItems.add(buildMenuListItem(R.string.scripts_view_source, 0, 0,
  1518. + info.ParserError == null || info.ParserError.isEmpty()));
  1519. +
  1520. + ListMenu.Delegate delegate = (model) -> {
  1521. + int textId = model.get(ListMenuItemProperties.TITLE_ID);
  1522. + if (textId == R.string.remove) {
  1523. + UserScriptsBridge.RemoveScript(info.Key);
  1524. + } else if (textId == R.string.scripts_view_source) {
  1525. + UserScriptsBridge.getUtils().openSourceFile(info.Key);
  1526. + }
  1527. + };
  1528. + ((ScriptInfoRowViewHolder) holder)
  1529. + .setMenuButtonDelegate(() -> new BasicListMenu(mContext, menuItems, delegate));
  1530. + ((ScriptInfoRowViewHolder) holder)
  1531. + .setItemListener(new ScriptListBaseAdapter.ItemClickListener() {
  1532. + @Override
  1533. + public void onScriptOnOff(boolean Enabled) {
  1534. + UserScriptsBridge.SetScriptEnabled(info.Key, Enabled);
  1535. + }
  1536. +
  1537. + @Override
  1538. + public void onScriptClicked() {}
  1539. + });
  1540. + }
  1541. +
  1542. + // @Override
  1543. + public void onDataUpdated(boolean enabled) {
  1544. + List<ScriptInfo> list = UserScriptsBridge.getUserScriptItems();
  1545. + if (enabled == false) {
  1546. + for (ScriptInfo script : list) {
  1547. + script.ForceDisabled = true;
  1548. + }
  1549. + }
  1550. + setDisplayedScriptInfo(list);
  1551. + }
  1552. + }
  1553. +
  1554. + private TextView mAddButton;
  1555. + private RecyclerView mRecyclerView;
  1556. + private ScriptListAdapter mAdapter;
  1557. + private FragmentWindowAndroid mWindowAndroid;
  1558. +
  1559. + public ScriptListPreference(Context context, AttributeSet attrs) {
  1560. + super(context, attrs);
  1561. + mAdapter = new ScriptListAdapter(context);
  1562. + }
  1563. +
  1564. + public void setWindowAndroid(FragmentWindowAndroid windowAndroid) {
  1565. + mWindowAndroid = windowAndroid;
  1566. + }
  1567. +
  1568. + @Override
  1569. + public void onBindViewHolder(PreferenceViewHolder holder) {
  1570. + super.onBindViewHolder(holder);
  1571. +
  1572. + mAddButton = (TextView) holder.findViewById(R.id.add_script);
  1573. + mAddButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
  1574. + TintedDrawable.constructTintedDrawable(
  1575. + getContext(), R.drawable.plus, R.color.default_control_color_active),
  1576. + null, null, null);
  1577. + mAddButton.setOnClickListener(view -> {
  1578. + UserScriptsBridge.SelectAndAddScriptFromFile(mWindowAndroid);
  1579. + });
  1580. +
  1581. + mRecyclerView = (RecyclerView) holder.findViewById(R.id.script_list);
  1582. + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  1583. + mRecyclerView.setLayoutManager(layoutManager);
  1584. + mRecyclerView.addItemDecoration(
  1585. + new DividerItemDecoration(getContext(), layoutManager.getOrientation()));
  1586. + mRecyclerView.setEnabled(this.isEnabled());
  1587. + UserScriptsBridge.RegisterLoadCallback(this);
  1588. +
  1589. + // We do not want the RecyclerView to be announced by screen readers every time
  1590. + // the view is bound.
  1591. + if (mRecyclerView.getAdapter() != mAdapter) {
  1592. + mRecyclerView.setAdapter(mAdapter);
  1593. + // Initialize script list.
  1594. + mAdapter.onDataUpdated(this.isEnabled());
  1595. + }
  1596. + }
  1597. +
  1598. + @Override
  1599. + public void setEnabled (boolean enabled) {
  1600. + super.setEnabled(enabled);
  1601. + if (mRecyclerView != null) mRecyclerView.setEnabled(enabled);
  1602. + NotifyScriptsChanged();
  1603. + }
  1604. +
  1605. + public void NotifyScriptsChanged() {
  1606. + mAdapter.onDataUpdated(this.isEnabled());
  1607. + }
  1608. +
  1609. + public void OnUserScriptLoaded(boolean result, String error) {
  1610. + if (result == false) {
  1611. + Toast toast = Toast.makeText(getContext(), error, Toast.LENGTH_LONG);
  1612. + toast.show();
  1613. + }
  1614. + }
  1615. +}
  1616. \ No newline at end of file
  1617. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1618. new file mode 100644
  1619. --- /dev/null
  1620. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsBridge.java
  1621. @@ -0,0 +1,178 @@
  1622. +/*
  1623. + This file is part of Bromite.
  1624. +
  1625. + Bromite is free software: you can redistribute it and/or modify
  1626. + it under the terms of the GNU General Public License as published by
  1627. + the Free Software Foundation, either version 3 of the License, or
  1628. + (at your option) any later version.
  1629. +
  1630. + Bromite is distributed in the hope that it will be useful,
  1631. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1632. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1633. + GNU General Public License for more details.
  1634. +
  1635. + You should have received a copy of the GNU General Public License
  1636. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1637. +*/
  1638. +
  1639. +package org.chromium.components.user_scripts;
  1640. +
  1641. +import java.util.ArrayList;
  1642. +import java.util.List;
  1643. +import java.lang.ref.WeakReference;
  1644. +
  1645. +import org.json.JSONArray;
  1646. +import org.json.JSONException;
  1647. +import org.json.JSONObject;
  1648. +
  1649. +import android.content.Context;
  1650. +import android.content.Intent;
  1651. +import android.net.Uri;
  1652. +import androidx.annotation.Nullable;
  1653. +
  1654. +import org.chromium.base.annotations.CalledByNative;
  1655. +import org.chromium.base.annotations.JNINamespace;
  1656. +import org.chromium.base.annotations.NativeMethods;
  1657. +import org.chromium.base.Log;
  1658. +import org.chromium.ui.base.WindowAndroid;
  1659. +
  1660. +import org.chromium.components.user_scripts.ScriptListPreference;
  1661. +import org.chromium.components.user_scripts.IUserScriptsUtils;
  1662. +
  1663. +@JNINamespace("user_scripts")
  1664. +public class UserScriptsBridge {
  1665. + private static final String TAG = "UserScript";
  1666. +
  1667. + static WeakReference<ScriptListPreference> observer;
  1668. +
  1669. + private static IUserScriptsUtils utilInstance;
  1670. +
  1671. + public static void registerUtils(IUserScriptsUtils instance) {
  1672. + utilInstance = instance;
  1673. + }
  1674. +
  1675. + public static IUserScriptsUtils getUtils() {
  1676. + return utilInstance;
  1677. + }
  1678. +
  1679. + public static boolean isEnabled() {
  1680. + return UserScriptsBridgeJni.get().isEnabled();
  1681. + }
  1682. +
  1683. + public static void setEnabled(boolean enabled) {
  1684. + UserScriptsBridgeJni.get().setEnabled(enabled);
  1685. + }
  1686. +
  1687. + public static void RemoveScript(String key) {
  1688. + UserScriptsBridgeJni.get().removeScript(key);
  1689. + }
  1690. +
  1691. + public static void SetScriptEnabled(String key,
  1692. + boolean enabled) {
  1693. + UserScriptsBridgeJni.get().setScriptEnabled(key, enabled);
  1694. + }
  1695. +
  1696. + public static void Reload() {
  1697. + UserScriptsBridgeJni.get().reload();
  1698. + }
  1699. +
  1700. + public static void SelectAndAddScriptFromFile(WindowAndroid window) {
  1701. + Context context = window.getContext().get();
  1702. +
  1703. + Intent fileSelector = new Intent(Intent.ACTION_OPEN_DOCUMENT);
  1704. + fileSelector.addCategory(Intent.CATEGORY_OPENABLE);
  1705. + fileSelector.setType("*/*");
  1706. + fileSelector.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  1707. +
  1708. + window.showIntent(fileSelector,
  1709. + new WindowAndroid.IntentCallback() {
  1710. + @Override
  1711. + public void onIntentCompleted(WindowAndroid window, int resultCode, Intent data) {
  1712. + if (data == null) return;
  1713. + Uri filePath = data.getData();
  1714. + UserScriptsBridgeJni.get().tryToInstall(filePath.toString());
  1715. + }
  1716. + },
  1717. + null);
  1718. + }
  1719. +
  1720. + public static void TryToInstall(String ScriptFullPath) {
  1721. + UserScriptsBridgeJni.get().tryToInstall(ScriptFullPath);
  1722. + }
  1723. +
  1724. + public static List<ScriptInfo> getUserScriptItems() {
  1725. + List<ScriptInfo> list = new ArrayList<>();
  1726. + try {
  1727. + String json = UserScriptsBridgeJni.get().getScriptsInfo();
  1728. +
  1729. + JSONObject jsonObject = new JSONObject(json);
  1730. +
  1731. + JSONArray scripts = jsonObject.names();
  1732. + if (scripts != null) {
  1733. + Log.i(TAG, "User Scripts Loaded: %s", json);
  1734. + Log.i(TAG, "Totals scripts: %s", Integer.toString(scripts.length()));
  1735. + for (int i = 0; i < scripts.length(); i++) {
  1736. + String key = (String) scripts.get(i);
  1737. + JSONObject script = jsonObject.getJSONObject(key);
  1738. +
  1739. + ScriptInfo si = new ScriptInfo();
  1740. + si.Key = key;
  1741. + list.add(si);
  1742. +
  1743. + if(script.has("name")) si.Name = script.getString("name");
  1744. + if(script.has("description")) si.Description = script.getString("description");
  1745. + if(script.has("version")) si.Version = script.getString("version");
  1746. + if(script.has("file_path")) si.FilePath = script.getString("file_path");
  1747. + if(script.has("url_source")) si.UrlSource = script.getString("url_source");
  1748. + if(script.has("parser_error")) si.ParserError = script.getString("parser_error");
  1749. + if(script.has("force_disabled")) si.ForceDisabled = script.getBoolean("force_disabled");;
  1750. + si.Enabled = script.getBoolean("enabled");
  1751. + }
  1752. + } else {
  1753. + Log.i(TAG, "User Scripts list empty");
  1754. + }
  1755. + } catch (Exception e) {
  1756. + Log.e(TAG, "User Scripts Load Error", e.toString());
  1757. + }
  1758. + return list;
  1759. + }
  1760. +
  1761. + public static void RegisterLoadCallback(ScriptListPreference caller) {
  1762. + UserScriptsBridgeJni.get().registerLoadCallback();
  1763. + observer = new WeakReference<ScriptListPreference>(caller);
  1764. + }
  1765. +
  1766. + @CalledByNative
  1767. + private static void shouldRefreshUserScriptList() {
  1768. + ScriptListPreference reference = observer.get();
  1769. + if (reference != null) {
  1770. + reference.NotifyScriptsChanged();
  1771. + }
  1772. + }
  1773. +
  1774. + @CalledByNative
  1775. + private static void onUserScriptLoaded(boolean result, String error) {
  1776. + ScriptListPreference reference = observer.get();
  1777. + if (reference != null) {
  1778. + reference.OnUserScriptLoaded(result, error);
  1779. + }
  1780. + }
  1781. +
  1782. + @NativeMethods
  1783. + interface Natives {
  1784. + boolean isEnabled();
  1785. + void setEnabled(boolean enabled);
  1786. +
  1787. + String getScriptsInfo();
  1788. +
  1789. + void removeScript(String scriptKey);
  1790. + void setScriptEnabled(String scriptKey, boolean enabled);
  1791. +
  1792. + void reload();
  1793. + void selectAndAddScriptFromFile(WindowAndroid window);
  1794. + void tryToInstall(String scriptFullPath);
  1795. +
  1796. + void registerLoadCallback();
  1797. + }
  1798. +
  1799. +}
  1800. \ No newline at end of file
  1801. diff --git a/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  1802. new file mode 100755
  1803. --- /dev/null
  1804. +++ b/components/user_scripts/android/java/src/org/chromium/components/user_scripts/UserScriptsPreferences.java
  1805. @@ -0,0 +1,139 @@
  1806. +/*
  1807. + This file is part of Bromite.
  1808. +
  1809. + Bromite is free software: you can redistribute it and/or modify
  1810. + it under the terms of the GNU General Public License as published by
  1811. + the Free Software Foundation, either version 3 of the License, or
  1812. + (at your option) any later version.
  1813. +
  1814. + Bromite is distributed in the hope that it will be useful,
  1815. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1816. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1817. + GNU General Public License for more details.
  1818. +
  1819. + You should have received a copy of the GNU General Public License
  1820. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1821. +*/
  1822. +
  1823. +package org.chromium.components.user_scripts;
  1824. +
  1825. +import android.app.Activity;
  1826. +import android.app.AlertDialog;
  1827. +import android.content.Context;
  1828. +import android.content.Intent;
  1829. +import android.content.DialogInterface;
  1830. +import android.os.Bundle;
  1831. +import android.provider.Browser;
  1832. +import android.net.Uri;
  1833. +import android.view.MenuItem;
  1834. +import android.view.View;
  1835. +
  1836. +import androidx.preference.Preference;
  1837. +import androidx.preference.PreferenceFragmentCompat;
  1838. +
  1839. +import org.chromium.base.Log;
  1840. +import org.chromium.ui.base.WindowAndroid;
  1841. +import org.chromium.ui.base.ActivityWindowAndroid;
  1842. +
  1843. +import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
  1844. +import org.chromium.components.browser_ui.settings.SettingsUtils;
  1845. +import org.chromium.components.browser_ui.settings.TextMessagePreference;
  1846. +
  1847. +import org.chromium.components.user_scripts.UserScriptsBridge;
  1848. +import org.chromium.components.user_scripts.FragmentWindowAndroid;
  1849. +
  1850. +public class UserScriptsPreferences
  1851. + extends PreferenceFragmentCompat
  1852. + implements SettingsUtils.ISupportHelpAndFeedback {
  1853. +
  1854. + private static final String PREF_ENABLED_SWITCH = "enabled_switch";
  1855. + private static final String PREF_SCRIPTLISTPREFERENCE = "script_list";
  1856. +
  1857. + public static final String EXTRA_SCRIPT_FILE = "org.chromium.chrome.preferences.script_file";
  1858. +
  1859. + private FragmentWindowAndroid mWindowAndroid;
  1860. +
  1861. + @Override
  1862. + public void onDestroy() {
  1863. + if (mWindowAndroid != null) mWindowAndroid.destroy();
  1864. + super.onDestroy();
  1865. + }
  1866. +
  1867. + @Override
  1868. + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
  1869. + getActivity().setTitle(R.string.prefs_userscripts_settings);
  1870. + SettingsUtils.addPreferencesFromResource(this, R.xml.userscripts_preferences);
  1871. +
  1872. + ChromeSwitchPreference enabledSwitch =
  1873. + (ChromeSwitchPreference) findPreference(PREF_ENABLED_SWITCH);
  1874. + ScriptListPreference listPreference =
  1875. + (ScriptListPreference) findPreference(PREF_SCRIPTLISTPREFERENCE);
  1876. +
  1877. + boolean enabled = UserScriptsBridge.isEnabled();
  1878. + enabledSwitch.setChecked(enabled);
  1879. + listPreference.setEnabled(enabled);
  1880. + enabledSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  1881. + UserScriptsBridge.setEnabled((boolean) newValue);
  1882. + listPreference.setEnabled((boolean) newValue);
  1883. + return true;
  1884. + });
  1885. +
  1886. + mWindowAndroid = new FragmentWindowAndroid(getContext(), this);
  1887. + listPreference.setWindowAndroid(mWindowAndroid);
  1888. + }
  1889. +
  1890. + @Override
  1891. + public void onActivityResult(int requestCode, int resultCode, Intent data) {
  1892. + // handle picker callback from SelectFileDialog
  1893. + mWindowAndroid.onActivityResult(requestCode, resultCode, data);
  1894. + }
  1895. +
  1896. + public void onHelpAndFeebackPressed() {
  1897. + Context context = getContext();
  1898. +
  1899. + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/UserScripts"));
  1900. + // Let Chromium know that this intent is from Chromium, so that it does not close the app when
  1901. + // the user presses 'back' button.
  1902. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
  1903. + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
  1904. + intent.setPackage(context.getPackageName());
  1905. + context.startActivity(intent);
  1906. + }
  1907. +
  1908. + public static Bundle createFragmentArgsForInstall(String filePath) {
  1909. + Bundle fragmentArgs = new Bundle();
  1910. + fragmentArgs.putSerializable(EXTRA_SCRIPT_FILE, filePath);
  1911. + return fragmentArgs;
  1912. + }
  1913. +
  1914. + @Override
  1915. + public void onActivityCreated(Bundle savedInstanceState) {
  1916. + super.onActivityCreated(savedInstanceState);
  1917. +
  1918. + String scriptToInstall = (String)getArguments().getSerializable(EXTRA_SCRIPT_FILE);
  1919. + if (scriptToInstall != null) {
  1920. + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
  1921. + @Override
  1922. + public void onClick(DialogInterface dialog, int which) {
  1923. + switch (which){
  1924. + case DialogInterface.BUTTON_POSITIVE:
  1925. + UserScriptsBridge.TryToInstall(scriptToInstall);
  1926. + break;
  1927. +
  1928. + case DialogInterface.BUTTON_NEGATIVE:
  1929. + break;
  1930. + }
  1931. + }
  1932. + };
  1933. +
  1934. + Context context = getContext();
  1935. + String message = context.getString(R.string.ask_to_install, scriptToInstall);
  1936. +
  1937. + AlertDialog.Builder builder = new AlertDialog.Builder(context);
  1938. + builder.setMessage(message)
  1939. + .setPositiveButton(context.getString(R.string.yes), dialogClickListener)
  1940. + .setNegativeButton(context.getString(R.string.no), dialogClickListener)
  1941. + .show();
  1942. + }
  1943. + }
  1944. +}
  1945. diff --git a/components/user_scripts/android/java_sources.gni b/components/user_scripts/android/java_sources.gni
  1946. new file mode 100644
  1947. --- /dev/null
  1948. +++ b/components/user_scripts/android/java_sources.gni
  1949. @@ -0,0 +1,18 @@
  1950. +# This file is part of Bromite.
  1951. +
  1952. +# Bromite is free software: you can redistribute it and/or modify
  1953. +# it under the terms of the GNU General Public License as published by
  1954. +# the Free Software Foundation, either version 3 of the License, or
  1955. +# (at your option) any later version.
  1956. +
  1957. +# Bromite is distributed in the hope that it will be useful,
  1958. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  1959. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1960. +# GNU General Public License for more details.
  1961. +
  1962. +# You should have received a copy of the GNU General Public License
  1963. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1964. +
  1965. +userscripts_java_sources = [
  1966. + "//components/user_scripts/android/java/src/org/chromium/chrome/browser/user_scripts/UserScriptsUtils.java",
  1967. +]
  1968. diff --git a/components/user_scripts/android/user_scripts_bridge.cc b/components/user_scripts/android/user_scripts_bridge.cc
  1969. new file mode 100644
  1970. --- /dev/null
  1971. +++ b/components/user_scripts/android/user_scripts_bridge.cc
  1972. @@ -0,0 +1,174 @@
  1973. +/*
  1974. + This file is part of Bromite.
  1975. +
  1976. + Bromite is free software: you can redistribute it and/or modify
  1977. + it under the terms of the GNU General Public License as published by
  1978. + the Free Software Foundation, either version 3 of the License, or
  1979. + (at your option) any later version.
  1980. +
  1981. + Bromite is distributed in the hope that it will be useful,
  1982. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1983. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1984. + GNU General Public License for more details.
  1985. +
  1986. + You should have received a copy of the GNU General Public License
  1987. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1988. +*/
  1989. +
  1990. +#include <jni.h>
  1991. +#include <algorithm>
  1992. +#include <string>
  1993. +#include <vector>
  1994. +#include <sstream>
  1995. +#include <iterator>
  1996. +
  1997. +#include "base/android/callback_android.h"
  1998. +#include "base/android/jni_android.h"
  1999. +#include "base/android/jni_array.h"
  2000. +#include "base/android/jni_string.h"
  2001. +#include "base/android/scoped_java_ref.h"
  2002. +#include "components/embedder_support/android/browser_context/browser_context_handle.h"
  2003. +#include "ui/android/window_android.h"
  2004. +
  2005. +#include "components/user_scripts/android/user_scripts_jni_headers/UserScriptsBridge_jni.h"
  2006. +#include "../browser/userscripts_browser_client.h"
  2007. +#include "user_scripts_bridge.h"
  2008. +
  2009. +using base::android::AttachCurrentThread;
  2010. +using base::android::ConvertJavaStringToUTF8;
  2011. +using base::android::ConvertUTF16ToJavaString;
  2012. +using base::android::ConvertUTF8ToJavaString;
  2013. +using base::android::JavaParamRef;
  2014. +using base::android::JavaRef;
  2015. +using base::android::ScopedJavaGlobalRef;
  2016. +using base::android::ScopedJavaLocalRef;
  2017. +using content::BrowserContext;
  2018. +
  2019. +namespace {
  2020. +
  2021. +user_scripts::UserScriptsBrowserClient* GetUserScriptsBrowserClient() {
  2022. + return user_scripts::UserScriptsBrowserClient::GetInstance();
  2023. +}
  2024. +
  2025. +class CallbackObserver : public user_scripts::UserScriptLoader::Observer {
  2026. + private:
  2027. + void OnScriptsLoaded(user_scripts::UserScriptLoader* loader,
  2028. + content::BrowserContext* browser_context) override {
  2029. + user_scripts::ShouldRefreshUserScriptList(base::android::AttachCurrentThread());
  2030. + }
  2031. +
  2032. + void OnUserScriptLoaded(user_scripts::UserScriptLoader* loader,
  2033. + bool result, const std::string& error) override {
  2034. + user_scripts::OnUserScriptLoaded(base::android::AttachCurrentThread(),
  2035. + result, error);
  2036. + }
  2037. +
  2038. + void OnUserScriptLoaderDestroyed(user_scripts::UserScriptLoader* loader) override {}
  2039. +};
  2040. +
  2041. +CallbackObserver* g_userscripts_loader_observer = NULL;
  2042. +
  2043. +}
  2044. +
  2045. +namespace user_scripts {
  2046. +
  2047. +static jboolean JNI_UserScriptsBridge_IsEnabled(
  2048. + JNIEnv* env) {
  2049. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2050. + if (client == NULL) return false;
  2051. + return client->GetPrefs()->IsEnabled();
  2052. +}
  2053. +
  2054. +static void JNI_UserScriptsBridge_SetEnabled(
  2055. + JNIEnv* env,
  2056. + jboolean is_enabled) {
  2057. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2058. + if (client == NULL) return;
  2059. + client->GetPrefs()->SetEnabled(is_enabled);
  2060. + client->GetLoader()->StartLoad();
  2061. +}
  2062. +
  2063. +static base::android::ScopedJavaLocalRef<jstring> JNI_UserScriptsBridge_GetScriptsInfo(
  2064. + JNIEnv* env) {
  2065. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2066. + if (client == NULL) return ConvertUTF8ToJavaString(env, {});
  2067. +
  2068. + std::string json = client->GetPrefs()->GetScriptsInfo();
  2069. + return ConvertUTF8ToJavaString(env, json);
  2070. +}
  2071. +
  2072. +static void JNI_UserScriptsBridge_RemoveScript(
  2073. + JNIEnv* env,
  2074. + const JavaParamRef<jstring>& jscript_key) {
  2075. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2076. + if (client == NULL) return;
  2077. +
  2078. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2079. + client->GetLoader()->RemoveScript(script_key);
  2080. +}
  2081. +
  2082. +static void JNI_UserScriptsBridge_SetScriptEnabled(
  2083. + JNIEnv* env,
  2084. + const JavaParamRef<jstring>& jscript_key,
  2085. + jboolean is_enabled) {
  2086. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2087. + if (client == NULL) return;
  2088. +
  2089. + std::string script_key = base::android::ConvertJavaStringToUTF8(jscript_key);
  2090. + client->GetLoader()->SetScriptEnabled(script_key, is_enabled);
  2091. +}
  2092. +
  2093. +static void JNI_UserScriptsBridge_Reload(
  2094. + JNIEnv* env) {
  2095. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2096. + if (client == NULL) return;
  2097. +
  2098. + client->GetLoader()->StartLoad();
  2099. + user_scripts::ShouldRefreshUserScriptList(env);
  2100. +}
  2101. +
  2102. +static void JNI_UserScriptsBridge_SelectAndAddScriptFromFile(
  2103. + JNIEnv* env,
  2104. + const JavaParamRef<jobject>& jwindow_android) {
  2105. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2106. + if (client == NULL) return;
  2107. +
  2108. + client->GetLoader()->SelectAndAddScriptFromFile(
  2109. + ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android));
  2110. +}
  2111. +
  2112. +static void JNI_UserScriptsBridge_TryToInstall(JNIEnv* env,
  2113. + const JavaParamRef<jstring>& jscript_path) {
  2114. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2115. + if (client == NULL) return;
  2116. +
  2117. + std::string script_path = base::android::ConvertJavaStringToUTF8(jscript_path);
  2118. + base::FilePath path(script_path);
  2119. +
  2120. + client->GetLoader()->TryToInstall(path);
  2121. +}
  2122. +
  2123. +static void JNI_UserScriptsBridge_RegisterLoadCallback(
  2124. + JNIEnv* env) {
  2125. + user_scripts::UserScriptsBrowserClient* client = GetUserScriptsBrowserClient();
  2126. + if (client == NULL) return;
  2127. +
  2128. + if (g_userscripts_loader_observer == NULL) {
  2129. + g_userscripts_loader_observer = new CallbackObserver();
  2130. + client->GetLoader()->AddObserver(g_userscripts_loader_observer);
  2131. + }
  2132. +}
  2133. +
  2134. +static void ShouldRefreshUserScriptList(JNIEnv* env) {
  2135. + Java_UserScriptsBridge_shouldRefreshUserScriptList(env);
  2136. +}
  2137. +
  2138. +static void OnUserScriptLoaded(JNIEnv* env,
  2139. + bool result, const std::string& error) {
  2140. + base::android::ScopedJavaLocalRef<jstring> j_error =
  2141. + base::android::ConvertUTF8ToJavaString(env, error);
  2142. +
  2143. + Java_UserScriptsBridge_onUserScriptLoaded(env, result, j_error);
  2144. +}
  2145. +
  2146. +}
  2147. \ No newline at end of file
  2148. diff --git a/components/user_scripts/android/user_scripts_bridge.h b/components/user_scripts/android/user_scripts_bridge.h
  2149. new file mode 100644
  2150. --- /dev/null
  2151. +++ b/components/user_scripts/android/user_scripts_bridge.h
  2152. @@ -0,0 +1,31 @@
  2153. +/*
  2154. + This file is part of Bromite.
  2155. +
  2156. + Bromite is free software: you can redistribute it and/or modify
  2157. + it under the terms of the GNU General Public License as published by
  2158. + the Free Software Foundation, either version 3 of the License, or
  2159. + (at your option) any later version.
  2160. +
  2161. + Bromite is distributed in the hope that it will be useful,
  2162. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2163. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2164. + GNU General Public License for more details.
  2165. +
  2166. + You should have received a copy of the GNU General Public License
  2167. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2168. +*/
  2169. +
  2170. +#ifndef COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2171. +#define COMPONENTS_USERSCRIPS_HELPER_ANDROID_H_
  2172. +
  2173. +#include <jni.h>
  2174. +
  2175. +namespace user_scripts {
  2176. +
  2177. +static void ShouldRefreshUserScriptList(JNIEnv* env);
  2178. +static void OnUserScriptLoaded(JNIEnv* env,
  2179. + bool result, const std::string& error);
  2180. +
  2181. +} // namespace user_scripts
  2182. +
  2183. +#endif
  2184. \ No newline at end of file
  2185. diff --git a/components/user_scripts/browser/BUILD.gn b/components/user_scripts/browser/BUILD.gn
  2186. new file mode 100755
  2187. --- /dev/null
  2188. +++ b/components/user_scripts/browser/BUILD.gn
  2189. @@ -0,0 +1,91 @@
  2190. +# This file is part of Bromite.
  2191. +
  2192. +# Bromite is free software: you can redistribute it and/or modify
  2193. +# it under the terms of the GNU General Public License as published by
  2194. +# the Free Software Foundation, either version 3 of the License, or
  2195. +# (at your option) any later version.
  2196. +
  2197. +# Bromite is distributed in the hope that it will be useful,
  2198. +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  2199. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2200. +# GNU General Public License for more details.
  2201. +
  2202. +# You should have received a copy of the GNU General Public License
  2203. +# along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2204. +
  2205. +import("//build/config/features.gni")
  2206. +import("//tools/grit/grit_rule.gni")
  2207. +
  2208. +group("browser") {
  2209. + public_deps = [
  2210. + "//components/user_scripts/browser:browser_sources",
  2211. + ]
  2212. +}
  2213. +
  2214. +source_set("browser_sources") {
  2215. + visibility = [ "./*" ]
  2216. +
  2217. + sources = [
  2218. + "file_task_runner.cc",
  2219. + "file_task_runner.h",
  2220. + "userscripts_browser_client.cc",
  2221. + "userscripts_browser_client.h",
  2222. + "user_script_loader.cc",
  2223. + "user_script_loader.h",
  2224. + "user_script_prefs.cc",
  2225. + "user_script_prefs.h",
  2226. + "user_script_pref_info.cc",
  2227. + "user_script_pref_info.h",
  2228. + "ui/user_scripts_ui.h",
  2229. + "ui/user_scripts_ui.cc",
  2230. + ]
  2231. +
  2232. + deps = [
  2233. + ":userscripts_browser_resources",
  2234. + "//base:i18n",
  2235. + "//components/keyed_service/content",
  2236. + "//components/keyed_service/core",
  2237. + "//components/pref_registry",
  2238. + "//components/prefs",
  2239. + "//content/public/browser",
  2240. + "//crypto:platform",
  2241. + "//components/user_scripts/common",
  2242. + "//services/device/public/mojom",
  2243. + "//services/preferences/public/cpp",
  2244. + "//services/service_manager/public/cpp",
  2245. + "//third_party/blink/public/common",
  2246. + "//third_party/blink/public/mojom/frame",
  2247. + "//ui/display",
  2248. + ]
  2249. +
  2250. + public_deps = [
  2251. + "//content/public/common",
  2252. + ]
  2253. +
  2254. + configs += [
  2255. + "//build/config:precompiled_headers",
  2256. +
  2257. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
  2258. + "//build/config/compiler:no_size_t_to_int_warning",
  2259. + "//build/config/compiler:wexit_time_destructors",
  2260. + ]
  2261. +}
  2262. +
  2263. +group("closure_compile") {
  2264. + deps = [ "resources/user-script-ui:closure_compile" ]
  2265. +}
  2266. +
  2267. +grit("userscripts_browser_resources") {
  2268. + source = "resources/browser_resources.grd"
  2269. +
  2270. + output_dir = "$root_gen_dir/chrome"
  2271. + outputs = [
  2272. + "grit/userscripts_browser_resources.h",
  2273. + "userscripts_browser_resources.pak",
  2274. + ]
  2275. +
  2276. + deps = [
  2277. + "//chrome/browser/resources/web_app_internals:components",
  2278. + "//chrome/browser/ui/webui/internals/web_app:mojo_bindings_js",
  2279. + ]
  2280. +}
  2281. diff --git a/components/user_scripts/browser/file_task_runner.cc b/components/user_scripts/browser/file_task_runner.cc
  2282. new file mode 100755
  2283. --- /dev/null
  2284. +++ b/components/user_scripts/browser/file_task_runner.cc
  2285. @@ -0,0 +1,40 @@
  2286. +/*
  2287. + This file is part of Bromite.
  2288. +
  2289. + Bromite is free software: you can redistribute it and/or modify
  2290. + it under the terms of the GNU General Public License as published by
  2291. + the Free Software Foundation, either version 3 of the License, or
  2292. + (at your option) any later version.
  2293. +
  2294. + Bromite is distributed in the hope that it will be useful,
  2295. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2296. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2297. + GNU General Public License for more details.
  2298. +
  2299. + You should have received a copy of the GNU General Public License
  2300. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2301. +*/
  2302. +
  2303. +#include "file_task_runner.h"
  2304. +
  2305. +#include "base/sequenced_task_runner.h"
  2306. +#include "base/task/lazy_thread_pool_task_runner.h"
  2307. +#include "base/task/task_traits.h"
  2308. +
  2309. +namespace user_scripts {
  2310. +
  2311. +namespace {
  2312. +
  2313. +base::LazyThreadPoolSequencedTaskRunner g_us_task_runner =
  2314. + LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
  2315. + base::TaskTraits(base::MayBlock(),
  2316. + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  2317. + base::TaskPriority::USER_VISIBLE));
  2318. +
  2319. +} // namespace
  2320. +
  2321. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner() {
  2322. + return g_us_task_runner.Get();
  2323. +}
  2324. +
  2325. +} // namespace user_scripts
  2326. diff --git a/components/user_scripts/browser/file_task_runner.h b/components/user_scripts/browser/file_task_runner.h
  2327. new file mode 100755
  2328. --- /dev/null
  2329. +++ b/components/user_scripts/browser/file_task_runner.h
  2330. @@ -0,0 +1,34 @@
  2331. +/*
  2332. + This file is part of Bromite.
  2333. +
  2334. + Bromite is free software: you can redistribute it and/or modify
  2335. + it under the terms of the GNU General Public License as published by
  2336. + the Free Software Foundation, either version 3 of the License, or
  2337. + (at your option) any later version.
  2338. +
  2339. + Bromite is distributed in the hope that it will be useful,
  2340. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2341. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2342. + GNU General Public License for more details.
  2343. +
  2344. + You should have received a copy of the GNU General Public License
  2345. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2346. +*/
  2347. +
  2348. +#ifndef USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2349. +#define USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2350. +
  2351. +#include "base/memory/ref_counted.h"
  2352. +#include "base/task/task_traits.h"
  2353. +
  2354. +namespace base {
  2355. +class SequencedTaskRunner;
  2356. +}
  2357. +
  2358. +namespace user_scripts {
  2359. +
  2360. +scoped_refptr<base::SequencedTaskRunner> GetUserScriptsFileTaskRunner();
  2361. +
  2362. +} // namespace extensions
  2363. +
  2364. +#endif // USERSCRIPTS_BROWSER_FILE_TASK_RUNNER_H_
  2365. diff --git a/components/user_scripts/browser/resources/browser_resources.grd b/components/user_scripts/browser/resources/browser_resources.grd
  2366. new file mode 100644
  2367. --- /dev/null
  2368. +++ b/components/user_scripts/browser/resources/browser_resources.grd
  2369. @@ -0,0 +1,14 @@
  2370. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  2371. + <outputs>
  2372. + <output filename="grit/userscripts_browser_resources.h" type="rc_header">
  2373. + <emit emit_type='prepend'></emit>
  2374. + </output>
  2375. + <output filename="userscripts_browser_resources.pak" type="data_package" />
  2376. + </outputs>
  2377. + <release seq="1">
  2378. + <includes>
  2379. + <include name="IDR_USER_SCRIPTS_HTML" file="user-script-ui\user-scripts-ui.html" type="BINDATA" />
  2380. + <include name="IDR_USER_SCRIPTS_JS" file="user-script-ui\user-scripts-ui.js" type="BINDATA" />
  2381. + </includes>
  2382. + </release>
  2383. +</grit>
  2384. \ No newline at end of file
  2385. diff --git a/components/user_scripts/browser/resources/user-script-ui/BUILD.gn b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2386. new file mode 100644
  2387. --- /dev/null
  2388. +++ b/components/user_scripts/browser/resources/user-script-ui/BUILD.gn
  2389. @@ -0,0 +1,12 @@
  2390. +import("//third_party/closure_compiler/compile_js.gni")
  2391. +
  2392. +js_type_check("closure_compile") {
  2393. + deps = [ ":view_script_source" ]
  2394. +}
  2395. +
  2396. +js_library("view_script_source") {
  2397. + deps = [
  2398. + "//ui/webui/resources/js:cr.m",
  2399. + "//ui/webui/resources/js:util.m",
  2400. + ]
  2401. +}
  2402. \ No newline at end of file
  2403. diff --git a/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2404. new file mode 100644
  2405. --- /dev/null
  2406. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.html
  2407. @@ -0,0 +1,14 @@
  2408. +<!doctype html>
  2409. +<html lang="en">
  2410. +<head>
  2411. + <meta charset="utf-8">
  2412. + <title>Local State Debug Page</title>
  2413. + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
  2414. + <script type="module" src="user-scripts-ui.js"></script>
  2415. +</head>
  2416. +<body>
  2417. + <pre id="content">
  2418. + Loading Script Source file...
  2419. + </pre>
  2420. +</body>
  2421. +</html>
  2422. \ No newline at end of file
  2423. diff --git a/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2424. new file mode 100644
  2425. --- /dev/null
  2426. +++ b/components/user_scripts/browser/resources/user-script-ui/user-scripts-ui.js
  2427. @@ -0,0 +1,9 @@
  2428. +import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
  2429. +import {$} from 'chrome://resources/js/util.m.js';
  2430. +
  2431. +document.addEventListener('DOMContentLoaded', function() {
  2432. + const urlParams = new URLSearchParams(window.location.search);
  2433. + sendWithPromise('requestSource', urlParams.get('key')).then(textContent => {
  2434. + $('content').textContent = textContent[0].content;
  2435. + });
  2436. +});
  2437. \ No newline at end of file
  2438. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.cc b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2439. new file mode 100644
  2440. --- /dev/null
  2441. +++ b/components/user_scripts/browser/ui/user_scripts_ui.cc
  2442. @@ -0,0 +1,148 @@
  2443. +/*
  2444. + This file is part of Bromite.
  2445. +
  2446. + Bromite is free software: you can redistribute it and/or modify
  2447. + it under the terms of the GNU General Public License as published by
  2448. + the Free Software Foundation, either version 3 of the License, or
  2449. + (at your option) any later version.
  2450. +
  2451. + Bromite is distributed in the hope that it will be useful,
  2452. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2453. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2454. + GNU General Public License for more details.
  2455. +
  2456. + You should have received a copy of the GNU General Public License
  2457. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2458. +*/
  2459. +
  2460. +
  2461. +#include <memory>
  2462. +
  2463. +#include "base/bind.h"
  2464. +#include "base/json/json_string_value_serializer.h"
  2465. +#include "base/macros.h"
  2466. +#include "base/memory/writable_shared_memory_region.h"
  2467. +#include "base/strings/string_util.h"
  2468. +#include "base/values.h"
  2469. +
  2470. +#include "chrome/browser/browser_process.h"
  2471. +#include "chrome/browser/profiles/profile.h"
  2472. +#include "chrome/common/url_constants.h"
  2473. +#include "chrome/grit/userscripts_browser_resources.h"
  2474. +#include "components/prefs/pref_service.h"
  2475. +#include "content/public/browser/web_ui.h"
  2476. +#include "content/public/browser/web_ui_controller.h"
  2477. +#include "content/public/browser/web_ui_data_source.h"
  2478. +#include "content/public/browser/web_ui_message_handler.h"
  2479. +
  2480. +#include "user_scripts_ui.h"
  2481. +#include "../userscripts_browser_client.h"
  2482. +#include "../../common/user_script.h"
  2483. +
  2484. +namespace {
  2485. +
  2486. +class UserScriptsUIHandler : public content::WebUIMessageHandler {
  2487. + public:
  2488. + UserScriptsUIHandler();
  2489. + ~UserScriptsUIHandler() override;
  2490. +
  2491. + // content::WebUIMessageHandler:
  2492. + void RegisterMessages() override;
  2493. +
  2494. + private:
  2495. + void HandleRequestSource(const base::ListValue* args);
  2496. + void OnScriptsLoaded(
  2497. + const std::string callback_id,
  2498. + const std::string script_key,
  2499. + std::unique_ptr<user_scripts::UserScriptList> user_scripts);
  2500. +
  2501. + std::unique_ptr<user_scripts::UserScriptList> loaded_scripts_;
  2502. +
  2503. + base::WeakPtrFactory<UserScriptsUIHandler> weak_factory_{this};
  2504. +
  2505. + DISALLOW_COPY_AND_ASSIGN(UserScriptsUIHandler);
  2506. +};
  2507. +
  2508. +UserScriptsUIHandler::UserScriptsUIHandler()
  2509. + : loaded_scripts_(new user_scripts::UserScriptList()) {
  2510. +}
  2511. +
  2512. +UserScriptsUIHandler::~UserScriptsUIHandler() {
  2513. +}
  2514. +
  2515. +void UserScriptsUIHandler::RegisterMessages() {
  2516. + web_ui()->RegisterMessageCallback(
  2517. + "requestSource",
  2518. + base::BindRepeating(&UserScriptsUIHandler::HandleRequestSource,
  2519. + base::Unretained(this)));
  2520. +}
  2521. +
  2522. +void UserScriptsUIHandler::HandleRequestSource(const base::ListValue* args) {
  2523. + AllowJavascript();
  2524. + std::string callback_id;
  2525. + CHECK(args->GetString(0, &callback_id));
  2526. +
  2527. + std::string script_key;
  2528. + if (args->GetString(1, &script_key) == false) {
  2529. + std::string json = "Missing key value.";
  2530. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2531. + return;
  2532. + }
  2533. +
  2534. + user_scripts::UserScriptsBrowserClient* client = user_scripts::UserScriptsBrowserClient::GetInstance();
  2535. + if (client == NULL) {
  2536. + std::string json = "User scripts disabled.";
  2537. + ResolveJavascriptCallback(base::Value(callback_id), base::Value(json));
  2538. + } else {
  2539. + std::unique_ptr<user_scripts::UserScriptList> scripts_to_load =
  2540. + std::move(loaded_scripts_);
  2541. + scripts_to_load->clear();
  2542. +
  2543. + client->GetLoader()->LoadScripts(std::move(scripts_to_load),
  2544. + base::BindOnce(
  2545. + &UserScriptsUIHandler::OnScriptsLoaded,
  2546. + weak_factory_.GetWeakPtr(),
  2547. + callback_id, script_key)
  2548. + );
  2549. + }
  2550. +}
  2551. +
  2552. +void UserScriptsUIHandler::OnScriptsLoaded(
  2553. + const std::string callback_id,
  2554. + const std::string script_key,
  2555. + std::unique_ptr<user_scripts::UserScriptList> user_scripts) {
  2556. + loaded_scripts_ = std::move(user_scripts);
  2557. +
  2558. + base::ListValue response;
  2559. + for (const std::unique_ptr<user_scripts::UserScript>& script : *loaded_scripts_) {
  2560. + if (script->key() == script_key) {
  2561. + auto scriptData = std::make_unique<base::DictionaryValue>();
  2562. + for (const std::unique_ptr<user_scripts::UserScript::File>& js_file :
  2563. + script->js_scripts()) {
  2564. + base::StringPiece contents = js_file->GetContent();
  2565. + scriptData->SetString("content", contents.data());
  2566. + }
  2567. + response.Append(std::move(scriptData));
  2568. + }
  2569. + }
  2570. +
  2571. + ResolveJavascriptCallback(base::Value(callback_id), response);
  2572. +}
  2573. +
  2574. +} // namespace
  2575. +
  2576. +namespace user_scripts {
  2577. +
  2578. +UserScriptsUI::UserScriptsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  2579. + content::WebUIDataSource* html_source =
  2580. + content::WebUIDataSource::Create(kChromeUIUserScriptsHost);
  2581. + html_source->SetDefaultResource(IDR_USER_SCRIPTS_HTML);
  2582. + html_source->AddResourcePath("user-scripts-ui.js", IDR_USER_SCRIPTS_JS);
  2583. + content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
  2584. + web_ui->AddMessageHandler(std::make_unique<UserScriptsUIHandler>());
  2585. +}
  2586. +
  2587. +UserScriptsUI::~UserScriptsUI() {
  2588. +}
  2589. +
  2590. +}
  2591. \ No newline at end of file
  2592. diff --git a/components/user_scripts/browser/ui/user_scripts_ui.h b/components/user_scripts/browser/ui/user_scripts_ui.h
  2593. new file mode 100644
  2594. --- /dev/null
  2595. +++ b/components/user_scripts/browser/ui/user_scripts_ui.h
  2596. @@ -0,0 +1,39 @@
  2597. +/*
  2598. + This file is part of Bromite.
  2599. +
  2600. + Bromite is free software: you can redistribute it and/or modify
  2601. + it under the terms of the GNU General Public License as published by
  2602. + the Free Software Foundation, either version 3 of the License, or
  2603. + (at your option) any later version.
  2604. +
  2605. + Bromite is distributed in the hope that it will be useful,
  2606. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2607. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2608. + GNU General Public License for more details.
  2609. +
  2610. + You should have received a copy of the GNU General Public License
  2611. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2612. +*/
  2613. +
  2614. +#ifndef USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2615. +#define USERSCRIPTS_BROWSER_UI_USER_SCRIPTS_UI_H_
  2616. +
  2617. +#include "base/macros.h"
  2618. +#include "content/public/browser/web_ui_controller.h"
  2619. +
  2620. +namespace user_scripts {
  2621. +
  2622. +const char kChromeUIUserScriptsHost[] = "user-scripts";
  2623. +
  2624. +class UserScriptsUI : public content::WebUIController {
  2625. + public:
  2626. + explicit UserScriptsUI(content::WebUI* web_ui);
  2627. + ~UserScriptsUI() override;
  2628. +
  2629. + private:
  2630. + DISALLOW_COPY_AND_ASSIGN(UserScriptsUI);
  2631. +};
  2632. +
  2633. +}
  2634. +
  2635. +#endif
  2636. \ No newline at end of file
  2637. diff --git a/components/user_scripts/browser/user_script_loader.cc b/components/user_scripts/browser/user_script_loader.cc
  2638. new file mode 100755
  2639. --- /dev/null
  2640. +++ b/components/user_scripts/browser/user_script_loader.cc
  2641. @@ -0,0 +1,719 @@
  2642. +/*
  2643. + This file is part of Bromite.
  2644. +
  2645. + Bromite is free software: you can redistribute it and/or modify
  2646. + it under the terms of the GNU General Public License as published by
  2647. + the Free Software Foundation, either version 3 of the License, or
  2648. + (at your option) any later version.
  2649. +
  2650. + Bromite is distributed in the hope that it will be useful,
  2651. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  2652. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  2653. + GNU General Public License for more details.
  2654. +
  2655. + You should have received a copy of the GNU General Public License
  2656. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  2657. +*/
  2658. +
  2659. +#include "user_script_loader.h"
  2660. +
  2661. +#include <stddef.h>
  2662. +
  2663. +#include <set>
  2664. +#include <string>
  2665. +#include <utility>
  2666. +
  2667. +#include "base/bind.h"
  2668. +#include "base/memory/writable_shared_memory_region.h"
  2669. +#include "base/strings/string_util.h"
  2670. +#include "base/strings/strcat.h"
  2671. +#include "base/files/file.h"
  2672. +#include "base/files/file_util.h"
  2673. +#include "base/files/file_enumerator.h"
  2674. +#include "base/i18n/file_util_icu.h"
  2675. +#include "base/path_service.h"
  2676. +#include "base/base_paths_android.h"
  2677. +#include "base/strings/utf_string_conversions.h"
  2678. +#include "base/android/content_uri_utils.h"
  2679. +#include "base/android/jni_android.h"
  2680. +#include "base/task/task_traits.h"
  2681. +#include "base/version.h"
  2682. +
  2683. +#include "crypto/sha2.h"
  2684. +#include "base/base64.h"
  2685. +
  2686. +#include "build/build_config.h"
  2687. +#include "content/public/browser/browser_context.h"
  2688. +#include "content/public/browser/browser_task_traits.h"
  2689. +#include "content/public/browser/browser_thread.h"
  2690. +#include "content/public/browser/notification_service.h"
  2691. +#include "content/public/browser/notification_types.h"
  2692. +#include "content/public/browser/render_process_host.h"
  2693. +#include "ui/shell_dialogs/select_file_dialog.h"
  2694. +#include "content/browser/file_system_access/file_system_chooser.h"
  2695. +#include "chrome/browser/ui/chrome_select_file_policy.h"
  2696. +#include "ui/android/window_android.h"
  2697. +
  2698. +#include "../common/user_scripts_features.h"
  2699. +#include "../common/extension_messages.h"
  2700. +#include "file_task_runner.h"
  2701. +#include "user_script_prefs.h"
  2702. +#include "user_script_pref_info.h"
  2703. +
  2704. +using content::BrowserThread;
  2705. +using content::BrowserContext;
  2706. +
  2707. +namespace user_scripts {
  2708. +
  2709. +namespace {
  2710. +
  2711. +static const base::StringPiece kUserScriptBegin("// ==UserScript==");
  2712. +static const base::StringPiece kUserScriptEnd("// ==/UserScript==");
  2713. +static const base::StringPiece kNamespaceDeclaration("// @namespace");
  2714. +static const base::StringPiece kNameDeclaration("// @name");
  2715. +static const base::StringPiece kVersionDeclaration("// @version");
  2716. +static const base::StringPiece kDescriptionDeclaration("// @description");
  2717. +static const base::StringPiece kIncludeDeclaration("// @include");
  2718. +static const base::StringPiece kExcludeDeclaration("// @exclude");
  2719. +static const base::StringPiece kMatchDeclaration("// @match");
  2720. +static const base::StringPiece kExcludeMatchDeclaration("// @exclude_match");
  2721. +static const base::StringPiece kRunAtDeclaration("// @run-at");
  2722. +static const base::StringPiece kRunAtDocumentStartValue("document-start");
  2723. +static const base::StringPiece kRunAtDocumentEndValue("document-end");
  2724. +static const base::StringPiece kRunAtDocumentIdleValue("document-idle");
  2725. +static const base::StringPiece kUrlSourceDeclaration("// @url");
  2726. +static const base::StringPiece kUrlHomePageDeclaration("// @homepage");
  2727. +
  2728. +// internal use
  2729. +static const base::StringPiece kParserError("// @error");
  2730. +static const base::StringPiece kForceDisabled("// @disabled");
  2731. +
  2732. +bool invalidChar(unsigned char c)
  2733. +{
  2734. + return !(c>=0 && c <128);
  2735. +}
  2736. +
  2737. +void stripUnicode(std::string& str)
  2738. +{
  2739. + str.erase(remove_if(str.begin(),str.end(), invalidChar), str.end());
  2740. +}
  2741. +
  2742. +// Helper function to parse greasesmonkey headers
  2743. +bool GetDeclarationValue(const base::StringPiece& line,
  2744. + const base::StringPiece& prefix,
  2745. + std::string* value) {
  2746. + base::StringPiece::size_type index = line.find(prefix);
  2747. + if (index == base::StringPiece::npos)
  2748. + return false;
  2749. +
  2750. + std::string temp(line.data() + index + prefix.length(),
  2751. + line.length() - index - prefix.length());
  2752. +
  2753. + if (temp.empty() || !base::IsUnicodeWhitespace(temp[0]))
  2754. + return false;
  2755. +
  2756. + base::TrimWhitespaceASCII(temp, base::TRIM_ALL, value);
  2757. + return true;
  2758. +}
  2759. +
  2760. +} // namespace
  2761. +
  2762. +// static
  2763. +bool UserScriptLoader::ParseMetadataHeader(const base::StringPiece& script_text,
  2764. + std::unique_ptr<UserScript>& script,
  2765. + bool *found_metadata,
  2766. + std::string& error_message) {
  2767. + // http://wiki.greasespot.net/Metadata_block
  2768. + base::StringPiece line;
  2769. + size_t line_start = 0;
  2770. + size_t line_end = line_start;
  2771. + *found_metadata = false;
  2772. +
  2773. + while (line_start < script_text.length()) {
  2774. + line_end = script_text.find('\n', line_start);
  2775. +
  2776. + // Handle the case where there is no trailing newline in the file.
  2777. + if (line_end == std::string::npos)
  2778. + line_end = script_text.length() - 1;
  2779. +
  2780. + line = base::StringPiece(script_text.data() + line_start,
  2781. + line_end - line_start);
  2782. +
  2783. + if (!*found_metadata) {
  2784. + if (base::StartsWith(line, kUserScriptBegin))
  2785. + *found_metadata = true;
  2786. + } else {
  2787. + if (base::StartsWith(line, kUserScriptEnd))
  2788. + break;
  2789. +
  2790. + std::string value;
  2791. + if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
  2792. + // We escape some characters that MatchPattern() considers special.
  2793. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2794. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2795. + script->add_glob(value);
  2796. + } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) {
  2797. + base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
  2798. + base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
  2799. + script->add_exclude_glob(value);
  2800. + } else if (GetDeclarationValue(line, kNamespaceDeclaration, &value)) {
  2801. + script->set_name_space(value);
  2802. + } else if (GetDeclarationValue(line, kNameDeclaration, &value)) {
  2803. + script->set_name(value);
  2804. + } else if (GetDeclarationValue(line, kVersionDeclaration, &value)) {
  2805. + base::Version version(value);
  2806. + if (version.IsValid())
  2807. + script->set_version(version.GetString());
  2808. + } else if (GetDeclarationValue(line, kDescriptionDeclaration, &value)) {
  2809. + script->set_description(value);
  2810. + } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
  2811. + URLPattern pattern(UserScript::ValidUserScriptSchemes());
  2812. + if (URLPattern::ParseResult::kSuccess != pattern.Parse(value)) {
  2813. + error_message = "Invalid UserScript Schema " + value;
  2814. + return false;
  2815. + }
  2816. + script->add_url_pattern(pattern);
  2817. + } else if (GetDeclarationValue(line, kExcludeMatchDeclaration, &value)) {
  2818. + URLPattern exclude(UserScript::ValidUserScriptSchemes());
  2819. + if (URLPattern::ParseResult::kSuccess != exclude.Parse(value)) {
  2820. + error_message = "Invalid UserScript Schema " + value;
  2821. + return false;
  2822. + }
  2823. + script->add_exclude_url_pattern(exclude);
  2824. + } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
  2825. + if (value == kRunAtDocumentStartValue)
  2826. + script->set_run_location(UserScript::DOCUMENT_START);
  2827. + else if (value == kRunAtDocumentEndValue)
  2828. + script->set_run_location(UserScript::DOCUMENT_END);
  2829. + else if (value == kRunAtDocumentIdleValue)
  2830. + script->set_run_location(UserScript::DOCUMENT_IDLE);
  2831. + else {
  2832. + error_message = "Invalid RunAtDeclaration " + value;
  2833. + return false;
  2834. + }
  2835. + } else if (GetDeclarationValue(line, kUrlSourceDeclaration, &value) ||
  2836. + GetDeclarationValue(line, kUrlHomePageDeclaration, &value)) {
  2837. + script->set_url_source(value);
  2838. + } else if (GetDeclarationValue(line, kParserError, &value)) {
  2839. + script->set_parser_error(value);
  2840. + } else if (GetDeclarationValue(line, kForceDisabled, &value)) {
  2841. + script->set_force_disabled();
  2842. + }
  2843. +
  2844. + // TODO(aa): Handle more types of metadata.
  2845. + }
  2846. +
  2847. + line_start = line_end + 1;
  2848. + }
  2849. +
  2850. + // If no patterns were specified, default to @include *. This is what
  2851. + // Greasemonkey does.
  2852. + if (script->globs().empty() && script->url_patterns().is_empty())
  2853. + script->add_glob("*");
  2854. +
  2855. + return true;
  2856. +}
  2857. +
  2858. +// static
  2859. +bool LoadUserScriptFromFile(
  2860. + const base::FilePath& user_script_path, const GURL& original_url,
  2861. + std::unique_ptr<UserScript>& script,
  2862. + bool* found_metadata,
  2863. + std::u16string* error) {
  2864. +
  2865. + base::File infile;
  2866. + if (user_script_path.IsContentUri()) {
  2867. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  2868. + LOG(INFO) << "UserScriptLoader: path " << user_script_path << " is a content uri";
  2869. +
  2870. + infile = OpenContentUriForRead(user_script_path);
  2871. + } else {
  2872. + infile = base::File(user_script_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
  2873. + }
  2874. +
  2875. + if (!infile.IsValid()) {
  2876. + *error = base::ASCIIToUTF16("Cannot open script source.");
  2877. + return false;
  2878. + }
  2879. +
  2880. + auto length = infile.GetLength();
  2881. + if (length<=0) {
  2882. + *error = base::ASCIIToUTF16("File is empty.");
  2883. + return false;
  2884. + }
  2885. +
  2886. + auto buffer = std::vector<char>(length);
  2887. + int bytes_read = infile.Read(0, buffer.data(), length);
  2888. + if (bytes_read == -1) {
  2889. + *error = base::ASCIIToUTF16("Could not read source file.");
  2890. + return false;
  2891. + }
  2892. +
  2893. + std::string content(buffer.begin(), buffer.end());
  2894. + if (!base::IsStringUTF8(content)) {
  2895. + *error = base::ASCIIToUTF16("User script must be UTF8 encoded.");
  2896. + return false;
  2897. + }
  2898. +
  2899. + std::string detailed_error;
  2900. + bool parseResult = UserScriptLoader::ParseMetadataHeader(content, script,
  2901. + found_metadata, detailed_error);
  2902. + if (parseResult == false || *found_metadata == false) {
  2903. + *error = base::ASCIIToUTF16("Invalid script header. " + detailed_error);
  2904. + return false;
  2905. + }
  2906. +
  2907. + script->set_match_origin_as_fallback(MatchOriginAsFallbackBehavior::kNever);
  2908. +
  2909. + // remove unicode chars and set content into File
  2910. + stripUnicode(content);
  2911. + std::unique_ptr<UserScript::File> file(new UserScript::File());
  2912. + file->set_content(content);
  2913. + file->set_url(GURL(/*script_key*/ "script.js")); // name doesn't matter
  2914. +
  2915. + // create SHA256 of file
  2916. + char raw[crypto::kSHA256Length] = {0};
  2917. + std::string key;
  2918. + crypto::SHA256HashString(content, raw, crypto::kSHA256Length);
  2919. + base::Base64Encode(base::StringPiece(raw, crypto::kSHA256Length), &key);
  2920. + file->set_key(key);
  2921. +
  2922. + script->js_scripts().push_back(std::move(file));
  2923. +
  2924. + // add into key the filename
  2925. + // this value is used in ui to discriminate scripts
  2926. + script->set_key(user_script_path.BaseName().value());
  2927. + return true;
  2928. +}
  2929. +
  2930. +// static
  2931. +bool GetOrCreatePath(base::FilePath& path) {
  2932. + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path);
  2933. + path = path.AppendASCII("userscripts");
  2934. +
  2935. + // create snippets directory if not exists
  2936. + if (!base::PathExists(path)) {
  2937. + LOG(INFO) << "Path " << path << " doesn't exists. Creating";
  2938. + base::File::Error error = base::File::FILE_OK;
  2939. + if (!base::CreateDirectoryAndGetError(path, &error)) {
  2940. + LOG(ERROR) <<
  2941. + "UserScriptLoader: failed to create directory: " << path
  2942. + << " with error code " << error;
  2943. + return false;
  2944. + }
  2945. + }
  2946. + return true;
  2947. +}
  2948. +
  2949. +// static
  2950. +void LoadUserScripts(UserScriptList* user_scripts_list) {
  2951. + base::FilePath path;
  2952. + if (GetOrCreatePath(path) == false) return;
  2953. +
  2954. + // enumerate all files from script path
  2955. + // we accept all files, but we check if it's a real
  2956. + // userscript
  2957. + base::FileEnumerator dir_enum(
  2958. + path,
  2959. + /*recursive=*/false, base::FileEnumerator::FILES);
  2960. + base::FilePath full_name;
  2961. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  2962. + std::unique_ptr<UserScript> userscript(new UserScript());
  2963. +
  2964. + std::u16string error;
  2965. + bool found_metadata;
  2966. + if (LoadUserScriptFromFile(full_name, GURL(), userscript, &found_metadata, &error)) {
  2967. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  2968. + LOG(INFO) << "UserScriptLoader: Found user script " << userscript->name() <<
  2969. + "-" << userscript->version() <<
  2970. + "-" << userscript->description();
  2971. +
  2972. + userscript->set_file_path(full_name.AsUTF8Unsafe());
  2973. + user_scripts_list->push_back(std::move(userscript));
  2974. + } else {
  2975. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  2976. + }
  2977. + }
  2978. +}
  2979. +
  2980. +UserScriptLoader::UserScriptLoader(BrowserContext* browser_context,
  2981. + UserScriptsPrefs* prefs)
  2982. + : loaded_scripts_(new UserScriptList()),
  2983. + ready_(false),
  2984. + browser_context_(browser_context),
  2985. + prefs_(prefs) {}
  2986. +
  2987. +UserScriptLoader::~UserScriptLoader() {
  2988. + for (auto& observer : observers_)
  2989. + observer.OnUserScriptLoaderDestroyed(this);
  2990. +}
  2991. +
  2992. +void UserScriptLoader::OnRenderProcessHostCreated(
  2993. + content::RenderProcessHost* process_host) {
  2994. + if (initial_load_complete()) {
  2995. + SendUpdate(process_host, shared_memory_);
  2996. + }
  2997. +}
  2998. +
  2999. +void UserScriptLoader::SetReady(bool ready) {
  3000. + bool was_ready = ready_;
  3001. + ready_ = ready;
  3002. + if (ready_ && !was_ready)
  3003. + AttemptLoad();
  3004. +}
  3005. +
  3006. +void UserScriptLoader::AttemptLoad() {
  3007. + int tryOut = prefs_->GetCurrentStartupTryout();
  3008. + if (tryOut >= 3) {
  3009. + LOG(INFO) << "UserScriptLoader: Possible crash detected. UserScript disabled";
  3010. + prefs_->SetEnabled(false);
  3011. + } else {
  3012. + prefs_->StartupTryout(tryOut+1);
  3013. + StartLoad();
  3014. + }
  3015. +}
  3016. +
  3017. +void UserScriptLoader::StartLoad() {
  3018. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3019. +
  3020. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3021. + LOG(INFO) << "UserScriptLoader: StartLoad";
  3022. +
  3023. + // Reload any loaded scripts, and clear out |loaded_scripts_| to indicate that
  3024. + // the scripts aren't currently ready.
  3025. + std::unique_ptr<UserScriptList> scripts_to_load = std::move(loaded_scripts_);
  3026. + scripts_to_load->clear();
  3027. +
  3028. + if (prefs_->IsEnabled()) {
  3029. + LoadScripts(std::move(scripts_to_load),
  3030. + base::BindOnce(&UserScriptLoader::OnScriptsLoaded,
  3031. + weak_factory_.GetWeakPtr()));
  3032. + } else {
  3033. + OnScriptsLoaded(std::move(scripts_to_load));
  3034. + }
  3035. +}
  3036. +
  3037. +// static
  3038. +base::ReadOnlySharedMemoryRegion UserScriptLoader::Serialize(
  3039. + const UserScriptList& scripts) {
  3040. + base::Pickle pickle;
  3041. + pickle.WriteUInt32(scripts.size());
  3042. + for (const std::unique_ptr<UserScript>& script : scripts) {
  3043. + // TODO(aa): This can be replaced by sending content script metadata to
  3044. + // renderers along with other extension data in ExtensionMsg_Loaded.
  3045. + // See crbug.com/70516.
  3046. + script->Pickle(&pickle);
  3047. + // Write scripts as 'data' so that we can read it out in the slave without
  3048. + // allocating a new string.
  3049. + for (const std::unique_ptr<UserScript::File>& js_file :
  3050. + script->js_scripts()) {
  3051. + base::StringPiece contents = js_file->GetContent();
  3052. + pickle.WriteData(contents.data(), contents.length());
  3053. + }
  3054. + for (const std::unique_ptr<UserScript::File>& css_file :
  3055. + script->css_scripts()) {
  3056. + base::StringPiece contents = css_file->GetContent();
  3057. + pickle.WriteData(contents.data(), contents.length());
  3058. + }
  3059. + }
  3060. +
  3061. + // Create the shared memory object.
  3062. + base::MappedReadOnlyRegion shared_memory =
  3063. + base::ReadOnlySharedMemoryRegion::Create(pickle.size());
  3064. + if (!shared_memory.IsValid())
  3065. + return {};
  3066. +
  3067. + // Copy the pickle to shared memory.
  3068. + memcpy(shared_memory.mapping.memory(), pickle.data(), pickle.size());
  3069. + return std::move(shared_memory.region);
  3070. +}
  3071. +
  3072. +void UserScriptLoader::AddObserver(Observer* observer) {
  3073. + observers_.AddObserver(observer);
  3074. +}
  3075. +
  3076. +void UserScriptLoader::RemoveObserver(Observer* observer) {
  3077. + observers_.RemoveObserver(observer);
  3078. +}
  3079. +
  3080. +void UserScriptLoader::OnScriptsLoaded(
  3081. + std::unique_ptr<UserScriptList> user_scripts) {
  3082. +
  3083. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3084. + LOG(INFO) << "UserScriptLoader: OnScriptsLoaded";
  3085. +
  3086. + // Check user preferences for loaded user scripts
  3087. + prefs_->CompareWithPrefs(*user_scripts);
  3088. + loaded_scripts_ = std::move(user_scripts);
  3089. +
  3090. + base::ReadOnlySharedMemoryRegion shared_memory;
  3091. + shared_memory =
  3092. + UserScriptLoader::Serialize(*loaded_scripts_);
  3093. +
  3094. + if (!shared_memory.IsValid()) {
  3095. + // This can happen if we run out of file descriptors. In that case, we
  3096. + // have a choice between silently omitting all user scripts for new tabs,
  3097. + // by nulling out shared_memory_, or only silently omitting new ones by
  3098. + // leaving the existing object in place. The second seems less bad, even
  3099. + // though it removes the possibility that freeing the shared memory block
  3100. + // would open up enough FDs for long enough for a retry to succeed.
  3101. +
  3102. + // Pretend the extension change didn't happen.
  3103. + return;
  3104. + }
  3105. +
  3106. + // We've got scripts ready to go.
  3107. + shared_memory_ = std::move(shared_memory);
  3108. +
  3109. + for (content::RenderProcessHost::iterator i(
  3110. + content::RenderProcessHost::AllHostsIterator());
  3111. + !i.IsAtEnd(); i.Advance()) {
  3112. + SendUpdate(i.GetCurrentValue(), shared_memory_);
  3113. + }
  3114. +
  3115. + // DCHECK(false); trying crash
  3116. + prefs_->StartupTryout(0);
  3117. +
  3118. + for (auto& observer : observers_)
  3119. + observer.OnScriptsLoaded(this, browser_context_);
  3120. +}
  3121. +
  3122. +void UserScriptLoader::SendUpdate(
  3123. + content::RenderProcessHost* process,
  3124. + const base::ReadOnlySharedMemoryRegion& shared_memory) {
  3125. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3126. + LOG(INFO) << "UserScriptLoader: SendUpdate";
  3127. +
  3128. + // If the process is being started asynchronously, early return. We'll end up
  3129. + // calling InitUserScripts when it's created which will call this again.
  3130. + base::ProcessHandle handle = process->GetProcess().Handle();
  3131. + if (!handle)
  3132. + return;
  3133. +
  3134. + base::ReadOnlySharedMemoryRegion region_for_process =
  3135. + shared_memory.Duplicate();
  3136. + if (!region_for_process.IsValid())
  3137. + return;
  3138. +
  3139. + process->Send(new ExtensionMsg_UpdateUserScripts(
  3140. + std::move(region_for_process)));
  3141. +}
  3142. +
  3143. +void LoadScriptsOnFileTaskRunner(
  3144. + std::unique_ptr<UserScriptList> user_scripts,
  3145. + UserScriptLoader::LoadScriptsCallback callback) {
  3146. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3147. + DCHECK(user_scripts.get());
  3148. +
  3149. + // load user scripts from path
  3150. + LoadUserScripts(user_scripts.get());
  3151. +
  3152. + // Explicit priority to prevent unwanted task priority inheritance.
  3153. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3154. + ->PostTask(FROM_HERE,
  3155. + base::BindOnce(std::move(callback), std::move(user_scripts)));
  3156. +}
  3157. +
  3158. +void UserScriptLoader::LoadScripts(
  3159. + std::unique_ptr<UserScriptList> user_scripts,
  3160. + LoadScriptsCallback callback) {
  3161. + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  3162. +
  3163. + GetUserScriptsFileTaskRunner()->PostTask(
  3164. + FROM_HERE,
  3165. + base::BindOnce(&LoadScriptsOnFileTaskRunner, std::move(user_scripts),
  3166. + std::move(callback)));
  3167. +}
  3168. +
  3169. +void RemoveScriptsOnFileTaskRunner(
  3170. + const std::string& script_id,
  3171. + UserScriptLoader::RemoveScriptCallback callback) {
  3172. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3173. +
  3174. + base::FilePath path;
  3175. + if (GetOrCreatePath(path)) {
  3176. + base::FilePath file = path.Append(script_id);
  3177. + if (base::DeleteFile(file) == false) {
  3178. + LOG(ERROR) <<
  3179. + "ERROR: failed to delete file : " << path;
  3180. + }
  3181. + }
  3182. +
  3183. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3184. + ->PostTask(FROM_HERE,
  3185. + base::BindOnce(std::move(callback)));
  3186. +}
  3187. +
  3188. +void UserScriptLoader::OnScriptRemoved() {
  3189. + StartLoad();
  3190. +}
  3191. +
  3192. +void UserScriptLoader::RemoveScript(const std::string& script_id) {
  3193. + if (!prefs_->IsEnabled()) return;
  3194. + prefs_->RemoveScriptFromPrefs(script_id);
  3195. +
  3196. + GetUserScriptsFileTaskRunner()->PostTask(
  3197. + FROM_HERE,
  3198. + base::BindOnce(&RemoveScriptsOnFileTaskRunner,
  3199. + std::move(script_id),
  3200. + base::BindOnce(&UserScriptLoader::OnScriptRemoved,
  3201. + weak_factory_.GetWeakPtr())));
  3202. +}
  3203. +
  3204. +void UserScriptLoader::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3205. + if (!prefs_->IsEnabled()) return;
  3206. + prefs_->SetScriptEnabled(script_id, is_enabled);
  3207. + StartLoad();
  3208. +}
  3209. +
  3210. +void UserScriptLoader::SelectAndAddScriptFromFile(ui::WindowAndroid* nativeWindow) {
  3211. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  3212. +
  3213. + if (!prefs_->IsEnabled()) return;
  3214. +
  3215. + dialog_ = ui::SelectFileDialog::Create(
  3216. + this, std::make_unique<ChromeSelectFilePolicy>(nullptr /*web_contents*/));
  3217. +
  3218. + ui::SelectFileDialog::FileTypeInfo allowed_file_info;
  3219. + allowed_file_info.extensions = {{FILE_PATH_LITERAL("js")}};
  3220. + allowed_file_info.allowed_paths =
  3221. + ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
  3222. + base::FilePath suggested_name;
  3223. +
  3224. + std::vector<std::u16string> types;
  3225. + types.push_back(base::ASCIIToUTF16("*/*")); /*= java SelectFileDialog.ALL_TYPES*/
  3226. + std::pair<std::vector<std::u16string>, bool> accept_types = std::make_pair(
  3227. + types, false /*use_media_capture*/);
  3228. +
  3229. + dialog_->SelectFile(
  3230. + ui::SelectFileDialog::SELECT_OPEN_FILE,
  3231. + std::u16string() /* dialog title*/, suggested_name, &allowed_file_info,
  3232. + 0 /* file type index */, std::string() /* default file extension */,
  3233. + nativeWindow,
  3234. + &accept_types /* params */);
  3235. +}
  3236. +
  3237. +
  3238. +void LoadScriptFromPathOnFileTaskRunner(
  3239. + const base::FilePath& path,
  3240. + const std::string& display_name,
  3241. + UserScriptLoader::LoadSingleScriptCallback callback ) {
  3242. + DCHECK(GetUserScriptsFileTaskRunner()->RunsTasksInCurrentSequence());
  3243. +
  3244. + std::unique_ptr<UserScript> userscript(new UserScript());
  3245. + std::u16string error;
  3246. + bool found_metadata = false;
  3247. + bool loaded = LoadUserScriptFromFile(path, GURL(), userscript, &found_metadata, &error);
  3248. +
  3249. + bool result = loaded;
  3250. + if (result || found_metadata) {
  3251. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3252. + LOG(INFO) << "UserScriptLoader: found " << userscript->name() <<
  3253. + "-" << userscript->version() <<
  3254. + "-" << userscript->description();
  3255. + base::FilePath destination;
  3256. + if (GetOrCreatePath(destination) == false) {
  3257. + error = base::ASCIIToUTF16("Cannot create destination.");
  3258. + } else {
  3259. + // we need an unique file name
  3260. + if (display_name.empty() == false) {
  3261. + userscript->set_key(display_name);
  3262. + }
  3263. +
  3264. + // filename is original filename or display_name
  3265. + std::string file_name(userscript->key());
  3266. + base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
  3267. + destination = destination.Append(file_name);
  3268. +
  3269. + if (destination.ReferencesParent()) {
  3270. + error = base::ASCIIToUTF16("Invalid file name.");
  3271. + result = false;
  3272. + } else if (base::PathExists(destination)) {
  3273. + error = base::ASCIIToUTF16("User script already loaded.");
  3274. + result = false;
  3275. + } else {
  3276. + if (loaded) {
  3277. + // if is a correct userscript, copy it
  3278. + result = base::CopyFile(path, destination);
  3279. + if (result == false) {
  3280. + error = base::ASCIIToUTF16("Copy error.");
  3281. + }
  3282. + } else {
  3283. + // else, there is a parser error
  3284. + // write minimal values and the error string, so UI can show it
  3285. + std::string combined_string = base::StrCat({
  3286. + kUserScriptBegin, "\n",
  3287. + kNamespaceDeclaration, " ", userscript->name_space(), "\n",
  3288. + kNameDeclaration, " ", userscript->name(), "\n",
  3289. + kVersionDeclaration, " ", userscript->version(), "\n",
  3290. + kDescriptionDeclaration, " ", userscript->description(), "\n",
  3291. + kUrlSourceDeclaration, " ", userscript->url_source(), "\n",
  3292. + kParserError, " ", base::UTF16ToASCII(error), "\n",
  3293. + kForceDisabled, " true\n",
  3294. + kUserScriptEnd, "\n"
  3295. + });
  3296. +
  3297. + if (!base::WriteFile(destination, combined_string)) {
  3298. + error = base::ASCIIToUTF16("Cannot write.");
  3299. + result = false;
  3300. + }
  3301. + }
  3302. + }
  3303. + }
  3304. + }
  3305. +
  3306. + if (!error.empty()) {
  3307. + LOG(ERROR) << "UserScriptLoader: load error " << error;
  3308. + }
  3309. +
  3310. + // return to callback with eventually the error
  3311. + const std::string string_error = base::UTF16ToASCII(error);
  3312. + content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
  3313. + ->PostTask(FROM_HERE,
  3314. + base::BindOnce(std::move(callback), result,
  3315. + std::move(string_error)));
  3316. +}
  3317. +
  3318. +void UserScriptLoader::TryToInstall(const base::FilePath& script_path) {
  3319. + if (!prefs_->IsEnabled()) return;
  3320. +
  3321. + std::u16string file_display_name;
  3322. + base::MaybeGetFileDisplayName(script_path, &file_display_name);
  3323. +
  3324. + std::string display_name = script_path.BaseName().value();
  3325. + if (base::IsStringASCII(file_display_name))
  3326. + display_name = base::UTF16ToASCII(file_display_name);
  3327. +
  3328. + GetUserScriptsFileTaskRunner()->PostTask(
  3329. + FROM_HERE,
  3330. + base::BindOnce(
  3331. + &LoadScriptFromPathOnFileTaskRunner,
  3332. + script_path, display_name,
  3333. + base::BindOnce(
  3334. + &UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback,
  3335. + weak_factory_.GetWeakPtr()
  3336. + )
  3337. + ));
  3338. +}
  3339. +
  3340. +void UserScriptLoader::FileSelected(
  3341. + const base::FilePath& path, int index, void* params) {
  3342. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3343. + LOG(INFO) << "UserScriptLoader: FileSelected " << path;
  3344. +
  3345. + UserScriptLoader::TryToInstall(path);
  3346. +}
  3347. +
  3348. +void UserScriptLoader::LoadScriptFromPathOnFileTaskRunnerCallback(
  3349. + bool result, const std::string& error) {
  3350. + for (auto& observer : observers_)
  3351. + observer.OnUserScriptLoaded(this, result, error);
  3352. +
  3353. + StartLoad();
  3354. +}
  3355. +
  3356. +void UserScriptLoader::FileSelectionCanceled(
  3357. + void* params) {
  3358. +}
  3359. +
  3360. +} // namespace extensions
  3361. diff --git a/components/user_scripts/browser/user_script_loader.h b/components/user_scripts/browser/user_script_loader.h
  3362. new file mode 100755
  3363. --- /dev/null
  3364. +++ b/components/user_scripts/browser/user_script_loader.h
  3365. @@ -0,0 +1,171 @@
  3366. +/*
  3367. + This file is part of Bromite.
  3368. +
  3369. + Bromite is free software: you can redistribute it and/or modify
  3370. + it under the terms of the GNU General Public License as published by
  3371. + the Free Software Foundation, either version 3 of the License, or
  3372. + (at your option) any later version.
  3373. +
  3374. + Bromite is distributed in the hope that it will be useful,
  3375. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3376. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3377. + GNU General Public License for more details.
  3378. +
  3379. + You should have received a copy of the GNU General Public License
  3380. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3381. +*/
  3382. +
  3383. +#ifndef USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3384. +#define USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3385. +
  3386. +#include <map>
  3387. +#include <memory>
  3388. +#include <set>
  3389. +
  3390. +#include "base/callback_forward.h"
  3391. +#include "base/compiler_specific.h"
  3392. +#include "base/macros.h"
  3393. +#include "base/memory/read_only_shared_memory_region.h"
  3394. +#include "base/memory/weak_ptr.h"
  3395. +#include "base/observer_list.h"
  3396. +#include "base/scoped_observer.h"
  3397. +#include "content/public/browser/render_process_host_creation_observer.h"
  3398. +#include "ui/shell_dialogs/select_file_dialog.h"
  3399. +#include "content/browser/file_system_access/file_system_chooser.h"
  3400. +#include "ui/android/window_android.h"
  3401. +
  3402. +#include "../common/host_id.h"
  3403. +#include "../common/user_script.h"
  3404. +#include "user_script_prefs.h"
  3405. +
  3406. +namespace base {
  3407. +class ReadOnlySharedMemoryRegion;
  3408. +}
  3409. +
  3410. +namespace content {
  3411. +class BrowserContext;
  3412. +class RenderProcessHost;
  3413. +}
  3414. +
  3415. +namespace user_scripts {
  3416. +
  3417. +// Manages one "logical unit" of user scripts in shared memory by constructing a
  3418. +// new shared memory region when the set of scripts changes. Also notifies
  3419. +// renderers of new shared memory region when new renderers appear, or when
  3420. +// script reloading completes. Script loading lives on the file thread.
  3421. +class UserScriptLoader : public content::RenderProcessHostCreationObserver,
  3422. + public ui::SelectFileDialog::Listener {
  3423. + public:
  3424. + using LoadScriptsCallback =
  3425. + base::OnceCallback<void(std::unique_ptr<UserScriptList>)>;
  3426. + using LoadSingleScriptCallback =
  3427. + base::OnceCallback<void(bool result, const std::string& error)>;
  3428. +
  3429. + using RemoveScriptCallback =
  3430. + base::OnceCallback<void()>;
  3431. + class Observer {
  3432. + public:
  3433. + virtual void OnScriptsLoaded(UserScriptLoader* loader,
  3434. + content::BrowserContext* browser_context) = 0;
  3435. + virtual void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) = 0;
  3436. + virtual void OnUserScriptLoaded(UserScriptLoader* loader,
  3437. + bool result, const std::string& error) = 0;
  3438. + };
  3439. +
  3440. + // Parses the includes out of |script| and returns them in |includes|.
  3441. + static bool ParseMetadataHeader(const base::StringPiece& script_text,
  3442. + std::unique_ptr<UserScript>& script,
  3443. + bool *found_metadata,
  3444. + std::string& error_message);
  3445. +
  3446. + UserScriptLoader(content::BrowserContext* browser_context,
  3447. + UserScriptsPrefs* prefs);
  3448. + //const HostID& host_id);
  3449. + ~UserScriptLoader() override;
  3450. +
  3451. + // Initiates procedure to start loading scripts on the file thread.
  3452. + void StartLoad();
  3453. +
  3454. + // Returns true if we have any scripts ready.
  3455. + bool initial_load_complete() const { return shared_memory_.IsValid(); }
  3456. +
  3457. + // Pickle user scripts and return pointer to the shared memory.
  3458. + static base::ReadOnlySharedMemoryRegion Serialize(
  3459. + const user_scripts::UserScriptList& scripts);
  3460. +
  3461. + // Adds or removes observers.
  3462. + void AddObserver(Observer* observer);
  3463. + void RemoveObserver(Observer* observer);
  3464. +
  3465. + // Sets the flag if the initial set of hosts has finished loading; if it's
  3466. + // set to be true, calls AttempLoad() to bootstrap.
  3467. + void SetReady(bool ready);
  3468. +
  3469. + void RemoveScript(const std::string& script_id);
  3470. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3471. +
  3472. + void SelectAndAddScriptFromFile(ui::WindowAndroid* wa);
  3473. + void TryToInstall(const base::FilePath& script_path);
  3474. +
  3475. + void LoadScripts(std::unique_ptr<UserScriptList> user_scripts,
  3476. + LoadScriptsCallback callback);
  3477. +
  3478. + protected:
  3479. + content::BrowserContext* browser_context() const { return browser_context_; }
  3480. +
  3481. + UserScriptsPrefs* prefs() const { return prefs_; }
  3482. +
  3483. + private:
  3484. + void OnRenderProcessHostCreated(
  3485. + content::RenderProcessHost* process_host) override;
  3486. +
  3487. + // Attempts to initiate a load.
  3488. + void AttemptLoad();
  3489. +
  3490. + // Called once we have finished loading the scripts on the file thread.
  3491. + void OnScriptsLoaded(std::unique_ptr<UserScriptList> user_scripts);
  3492. +
  3493. + // Sends the renderer process a new set of user scripts. If
  3494. + // |changed_hosts| is not empty, this signals that only the scripts from
  3495. + // those hosts should be updated. Otherwise, all hosts will be
  3496. + // updated.
  3497. + void SendUpdate(content::RenderProcessHost* process,
  3498. + const base::ReadOnlySharedMemoryRegion& shared_memory);
  3499. +
  3500. + // Contains the scripts that were found the last time scripts were updated.
  3501. + base::ReadOnlySharedMemoryRegion shared_memory_;
  3502. +
  3503. + // List of scripts that are currently loaded. This is null when a load is in
  3504. + // progress.
  3505. + std::unique_ptr<UserScriptList> loaded_scripts_;
  3506. +
  3507. + // If the initial set of hosts has finished loading.
  3508. + bool ready_;
  3509. +
  3510. + // The browser_context for which the scripts managed here are installed.
  3511. + content::BrowserContext* browser_context_;
  3512. +
  3513. + // Manage load and store from preferences
  3514. + UserScriptsPrefs* prefs_;
  3515. +
  3516. + // The associated observers.
  3517. + base::ObserverList<Observer>::Unchecked observers_;
  3518. +
  3519. + void OnScriptRemoved();
  3520. +
  3521. + // Manage file dialog requests
  3522. + scoped_refptr<ui::SelectFileDialog> dialog_;
  3523. + void FileSelected(const base::FilePath& path,
  3524. + int index, void* params) override;
  3525. + void FileSelectionCanceled(void* params) override;
  3526. + void LoadScriptFromPathOnFileTaskRunnerCallback(
  3527. + bool result, const std::string& error );
  3528. +
  3529. + base::WeakPtrFactory<UserScriptLoader> weak_factory_{this};
  3530. +
  3531. + DISALLOW_COPY_AND_ASSIGN(UserScriptLoader);
  3532. +};
  3533. +
  3534. +} // namespace extensions
  3535. +
  3536. +#endif // USERSCRIPTS_BROWSER_USER_SCRIPT_LOADER_H_
  3537. diff --git a/components/user_scripts/browser/user_script_pref_info.cc b/components/user_scripts/browser/user_script_pref_info.cc
  3538. new file mode 100644
  3539. --- /dev/null
  3540. +++ b/components/user_scripts/browser/user_script_pref_info.cc
  3541. @@ -0,0 +1,34 @@
  3542. +/*
  3543. + This file is part of Bromite.
  3544. +
  3545. + Bromite is free software: you can redistribute it and/or modify
  3546. + it under the terms of the GNU General Public License as published by
  3547. + the Free Software Foundation, either version 3 of the License, or
  3548. + (at your option) any later version.
  3549. +
  3550. + Bromite is distributed in the hope that it will be useful,
  3551. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3552. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3553. + GNU General Public License for more details.
  3554. +
  3555. + You should have received a copy of the GNU General Public License
  3556. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3557. +*/
  3558. +
  3559. +#include "user_script_pref_info.h"
  3560. +
  3561. +namespace user_scripts {
  3562. +
  3563. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const std::string& name,
  3564. + const std::string& description,
  3565. + const base::Time& install_time,
  3566. + bool enabled)
  3567. + : install_time(install_time),
  3568. + enabled(enabled),
  3569. + name_(name),
  3570. + description_(description) {}
  3571. +
  3572. +UserScriptsListPrefs::ScriptInfo::ScriptInfo(const ScriptInfo& other) = default;
  3573. +UserScriptsListPrefs::ScriptInfo::~ScriptInfo() = default;
  3574. +
  3575. +}
  3576. \ No newline at end of file
  3577. diff --git a/components/user_scripts/browser/user_script_pref_info.h b/components/user_scripts/browser/user_script_pref_info.h
  3578. new file mode 100644
  3579. --- /dev/null
  3580. +++ b/components/user_scripts/browser/user_script_pref_info.h
  3581. @@ -0,0 +1,72 @@
  3582. +/*
  3583. + This file is part of Bromite.
  3584. +
  3585. + Bromite is free software: you can redistribute it and/or modify
  3586. + it under the terms of the GNU General Public License as published by
  3587. + the Free Software Foundation, either version 3 of the License, or
  3588. + (at your option) any later version.
  3589. +
  3590. + Bromite is distributed in the hope that it will be useful,
  3591. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3592. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3593. + GNU General Public License for more details.
  3594. +
  3595. + You should have received a copy of the GNU General Public License
  3596. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3597. +*/
  3598. +
  3599. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3600. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3601. +
  3602. +#include "base/values.h"
  3603. +#include "base/time/time.h"
  3604. +#include "components/keyed_service/core/keyed_service.h"
  3605. +
  3606. +namespace user_scripts {
  3607. +
  3608. +class UserScriptsListPrefs : public KeyedService {
  3609. + public:
  3610. + struct ScriptInfo {
  3611. + ScriptInfo(const std::string& name,
  3612. + const std::string& description,
  3613. + const base::Time& install_time,
  3614. + bool enabled);
  3615. + ScriptInfo(const ScriptInfo& other);
  3616. + ~ScriptInfo();
  3617. +
  3618. + const std::string& name() const { return name_; }
  3619. + void set_name(const std::string& name) { name_ = name; }
  3620. +
  3621. + const std::string& description() const { return description_; }
  3622. + void set_description(const std::string& description) { description_ = description; }
  3623. +
  3624. + const std::string& version() const { return version_; }
  3625. + void set_version(const std::string& version) { version_ = version; }
  3626. +
  3627. + const std::string& file_path() const { return file_path_; }
  3628. + void set_file_path(const std::string& file_path) { file_path_ = file_path; }
  3629. +
  3630. + const std::string& url_source() const { return url_source_; }
  3631. + void set_url_source(const std::string& url_source) { url_source_ = url_source; }
  3632. +
  3633. + const std::string& parser_error() const { return parser_error_; }
  3634. + void set_parser_error(const std::string& parser_error) { parser_error_ = parser_error; }
  3635. +
  3636. + base::Time install_time;
  3637. + bool enabled;
  3638. +
  3639. + bool force_disabled;
  3640. +
  3641. + private:
  3642. + std::string name_;
  3643. + std::string description_;
  3644. + std::string version_;
  3645. + std::string file_path_;
  3646. + std::string url_source_;
  3647. + std::string parser_error_;
  3648. + };
  3649. +};
  3650. +
  3651. +}
  3652. +
  3653. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREF_INFO_H_
  3654. \ No newline at end of file
  3655. diff --git a/components/user_scripts/browser/user_script_prefs.cc b/components/user_scripts/browser/user_script_prefs.cc
  3656. new file mode 100644
  3657. --- /dev/null
  3658. +++ b/components/user_scripts/browser/user_script_prefs.cc
  3659. @@ -0,0 +1,276 @@
  3660. +/*
  3661. + This file is part of Bromite.
  3662. +
  3663. + Bromite is free software: you can redistribute it and/or modify
  3664. + it under the terms of the GNU General Public License as published by
  3665. + the Free Software Foundation, either version 3 of the License, or
  3666. + (at your option) any later version.
  3667. +
  3668. + Bromite is distributed in the hope that it will be useful,
  3669. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3670. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3671. + GNU General Public License for more details.
  3672. +
  3673. + You should have received a copy of the GNU General Public License
  3674. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3675. +*/
  3676. +
  3677. +#include <map>
  3678. +
  3679. +#include "base/values.h"
  3680. +#include "base/strings/string_number_conversions.h"
  3681. +#include "base/json/json_writer.h"
  3682. +
  3683. +#include "chrome/browser/browser_process.h"
  3684. +#include "chrome/browser/profiles/profile.h"
  3685. +#include "chrome/browser/profiles/profile_manager.h"
  3686. +
  3687. +#include "components/prefs/pref_service.h"
  3688. +#include "components/prefs/scoped_user_pref_update.h"
  3689. +#include "components/pref_registry/pref_registry_syncable.h"
  3690. +#include "user_script_prefs.h"
  3691. +#include "user_script_pref_info.h"
  3692. +#include "../common/user_script.h"
  3693. +#include "../common/user_scripts_features.h"
  3694. +
  3695. +namespace user_scripts {
  3696. +
  3697. +namespace prefs {
  3698. + const char kUserScriptsEnabled[] = "userscripts.enabled";
  3699. +}
  3700. +
  3701. +namespace {
  3702. +
  3703. +const char kUserScriptsStartup[] = "userscripts.startup";
  3704. +
  3705. +const char kUserScriptsList[] = "userscripts.scripts";
  3706. +const char kScriptIsEnabled[] = "enabled";
  3707. +const char kScriptName[] = "name";
  3708. +const char kScriptDescription[] = "description";
  3709. +const char kScriptVersion[] = "version";
  3710. +const char kScriptInstallTime[] = "install_time";
  3711. +const char kScriptFilePath[] = "file_path";
  3712. +const char kScriptUrlSource[] = "url_source";
  3713. +const char kScriptParserError[] = "parser_error";
  3714. +const char kScriptForceDisabled[] = "force_disabled";
  3715. +
  3716. +class PrefUpdate : public DictionaryPrefUpdate {
  3717. + public:
  3718. + PrefUpdate(PrefService* service,
  3719. + const std::string& id,
  3720. + const std::string& path)
  3721. + : DictionaryPrefUpdate(service, path), id_(id) {}
  3722. +
  3723. + ~PrefUpdate() override = default;
  3724. +
  3725. + base::DictionaryValue* Get() override {
  3726. + base::DictionaryValue* dict = DictionaryPrefUpdate::Get();
  3727. + base::Value* dict_item =
  3728. + dict->FindKeyOfType(id_, base::Value::Type::DICTIONARY);
  3729. + if (!dict_item)
  3730. + dict_item = dict->SetKey(id_, base::Value(base::Value::Type::DICTIONARY));
  3731. + return static_cast<base::DictionaryValue*>(dict_item);
  3732. + }
  3733. +
  3734. + private:
  3735. + const std::string id_;
  3736. +
  3737. + DISALLOW_COPY_AND_ASSIGN(PrefUpdate);
  3738. +};
  3739. +
  3740. +bool GetInt64FromPref(const base::DictionaryValue* dict,
  3741. + const std::string& key,
  3742. + int64_t* value) {
  3743. + DCHECK(dict);
  3744. + std::string value_str;
  3745. + if (!dict->GetStringWithoutPathExpansion(key, &value_str)) {
  3746. + VLOG(2) << "Can't find key in local pref dictionary. Invalid key: " << key
  3747. + << ".";
  3748. + return false;
  3749. + }
  3750. +
  3751. + if (!base::StringToInt64(value_str, value)) {
  3752. + VLOG(2) << "Can't change string to int64_t. Invalid string value: "
  3753. + << value_str << ".";
  3754. + return false;
  3755. + }
  3756. +
  3757. + return true;
  3758. +}
  3759. +
  3760. +}
  3761. +
  3762. +UserScriptsPrefs::UserScriptsPrefs(
  3763. + PrefService* prefs)
  3764. + : prefs_(prefs) {
  3765. +}
  3766. +
  3767. +// static
  3768. +void UserScriptsPrefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  3769. + registry->RegisterBooleanPref(prefs::kUserScriptsEnabled, false);
  3770. + registry->RegisterIntegerPref(kUserScriptsStartup, 0);
  3771. + registry->RegisterDictionaryPref(kUserScriptsList);
  3772. +}
  3773. +
  3774. +bool UserScriptsPrefs::IsEnabled() {
  3775. + return prefs_->GetBoolean(prefs::kUserScriptsEnabled);
  3776. +}
  3777. +
  3778. +void UserScriptsPrefs::SetEnabled(bool enabled) {
  3779. + prefs_->SetBoolean(prefs::kUserScriptsEnabled, enabled);
  3780. + prefs_->CommitPendingWrite();
  3781. +}
  3782. +
  3783. +void UserScriptsPrefs::StartupTryout(int number) {
  3784. + prefs_->SetInteger(kUserScriptsStartup, number);
  3785. + prefs_->CommitPendingWrite();
  3786. +}
  3787. +
  3788. +int UserScriptsPrefs::GetCurrentStartupTryout() {
  3789. + return prefs_->GetInteger(kUserScriptsStartup);
  3790. +}
  3791. +
  3792. +void UserScriptsPrefs::CompareWithPrefs(UserScriptList& user_scripts) {
  3793. + if (IsEnabled() == false) {
  3794. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  3795. + LOG(INFO) << "UserScriptsPrefs: disabled by user";
  3796. +
  3797. + user_scripts.clear();
  3798. + return;
  3799. + }
  3800. +
  3801. + std::vector<std::string> all_scripts;
  3802. +
  3803. + auto it = user_scripts.begin();
  3804. + while (it != user_scripts.end())
  3805. + {
  3806. + std::string key = it->get()->key();
  3807. + all_scripts.push_back(key);
  3808. +
  3809. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> scriptInfo =
  3810. + UserScriptsPrefs::CreateScriptInfoFromPrefs(key);
  3811. +
  3812. + // add or update prefs
  3813. + scriptInfo->set_name(it->get()->name());
  3814. + scriptInfo->set_description(it->get()->description());
  3815. + scriptInfo->set_version(it->get()->version());
  3816. + scriptInfo->set_file_path(it->get()->file_path());
  3817. + scriptInfo->set_url_source(it->get()->url_source());
  3818. + scriptInfo->set_parser_error(it->get()->parser_error());
  3819. + scriptInfo->force_disabled = (it->get()->force_disabled());
  3820. +
  3821. + PrefUpdate update(prefs_, key, kUserScriptsList);
  3822. + base::DictionaryValue* script_dict = update.Get();
  3823. +
  3824. + script_dict->SetString(kScriptName, scriptInfo->name());
  3825. + script_dict->SetString(kScriptDescription, scriptInfo->description());
  3826. + script_dict->SetBoolean(kScriptIsEnabled, scriptInfo->enabled);
  3827. + script_dict->SetString(kScriptVersion, scriptInfo->version());
  3828. + script_dict->SetString(kScriptFilePath, scriptInfo->file_path());
  3829. + script_dict->SetString(kScriptUrlSource, scriptInfo->url_source());
  3830. + script_dict->SetString(kScriptParserError, scriptInfo->parser_error());
  3831. + script_dict->SetBoolean(kScriptForceDisabled, scriptInfo->force_disabled);
  3832. +
  3833. + std::string install_time_str =
  3834. + base::NumberToString(scriptInfo->install_time.ToInternalValue());
  3835. + script_dict->SetString(kScriptInstallTime, install_time_str);
  3836. +
  3837. + if (!scriptInfo->enabled) {
  3838. + it = user_scripts.erase(it);
  3839. + } else {
  3840. + ++it;
  3841. + }
  3842. + }
  3843. +
  3844. + // remove script from prefs if no more present
  3845. + std::vector<std::string> all_scripts_to_remove;
  3846. + const base::DictionaryValue* dict =
  3847. + prefs_->GetDictionary(kUserScriptsList);
  3848. + for (base::DictionaryValue::Iterator script_it(*dict); !script_it.IsAtEnd();
  3849. + script_it.Advance()) {
  3850. + const std::string& key = script_it.key();
  3851. +
  3852. + if (std::find(all_scripts.begin(), all_scripts.end(), key) == all_scripts.end()) {
  3853. + all_scripts_to_remove.push_back(key);
  3854. + }
  3855. + }
  3856. +
  3857. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  3858. + base::DictionaryValue* const update_dict = update.Get();
  3859. + for (auto key : all_scripts_to_remove) {
  3860. + update_dict->RemoveKey(key);
  3861. + }
  3862. +
  3863. + return;
  3864. +}
  3865. +
  3866. +std::string UserScriptsPrefs::GetScriptsInfo() {
  3867. + std::string json_string;
  3868. +
  3869. + const base::DictionaryValue* dict =
  3870. + prefs_->GetDictionary(kUserScriptsList);
  3871. +
  3872. + if (dict) {
  3873. + base::JSONWriter::WriteWithOptions(
  3874. + *dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
  3875. + base::TrimWhitespaceASCII(json_string, base::TRIM_ALL, &json_string);
  3876. + }
  3877. +
  3878. + return json_string;
  3879. +}
  3880. +
  3881. +std::unique_ptr<UserScriptsListPrefs::ScriptInfo> UserScriptsPrefs::CreateScriptInfoFromPrefs(
  3882. + const std::string& script_id) const {
  3883. +
  3884. + auto scriptInfo = std::make_unique<UserScriptsListPrefs::ScriptInfo>(
  3885. + script_id, "", base::Time::Now(), false);
  3886. +
  3887. + const base::DictionaryValue* scripts =
  3888. + prefs_->GetDictionary(kUserScriptsList);
  3889. + if (!scripts)
  3890. + return scriptInfo;
  3891. +
  3892. + const base::DictionaryValue* script = static_cast<const base::DictionaryValue*>(
  3893. + scripts->FindDictKey(script_id));
  3894. + if (!script)
  3895. + return scriptInfo;
  3896. +
  3897. + const std::string* name = script->FindStringKey(kScriptName);
  3898. + const std::string* description = script->FindStringKey(kScriptDescription);
  3899. + const std::string* version = script->FindStringKey(kScriptVersion);
  3900. + const std::string* file_path = script->FindStringKey(kScriptFilePath);
  3901. + const std::string* url_source = script->FindStringKey(kScriptUrlSource);
  3902. + const std::string* parser_error = script->FindStringKey(kScriptParserError);
  3903. +
  3904. + scriptInfo->set_name( name ? *name : "no name" );
  3905. + scriptInfo->set_description( description ? *description : "no description" );
  3906. + scriptInfo->set_version( version ? *version : "no version" );
  3907. + scriptInfo->enabled = script->FindBoolKey(kScriptIsEnabled).value_or(false);
  3908. + scriptInfo->set_file_path( file_path ? *file_path : "no file path" );
  3909. + scriptInfo->set_url_source( url_source ? *url_source : "" );
  3910. + scriptInfo->set_parser_error( parser_error ? *parser_error : "" );
  3911. + scriptInfo->force_disabled = script->FindBoolKey(kScriptForceDisabled).value_or(false);
  3912. +
  3913. + int64_t time_interval = 0;
  3914. + if (GetInt64FromPref(script, kScriptInstallTime, &time_interval)) {
  3915. + scriptInfo->install_time = base::Time::FromInternalValue(time_interval);
  3916. + }
  3917. +
  3918. + return scriptInfo;
  3919. +}
  3920. +
  3921. +void UserScriptsPrefs::RemoveScriptFromPrefs(const std::string& script_id) {
  3922. + DictionaryPrefUpdate update(prefs_, kUserScriptsList);
  3923. + base::DictionaryValue* const update_dict = update.Get();
  3924. + update_dict->RemoveKey(script_id);
  3925. +}
  3926. +
  3927. +void UserScriptsPrefs::SetScriptEnabled(const std::string& script_id, bool is_enabled) {
  3928. + PrefUpdate update(prefs_, script_id, kUserScriptsList);
  3929. + base::DictionaryValue* script_dict = update.Get();
  3930. + if (script_dict->FindBoolKey(kScriptForceDisabled).value_or(false))
  3931. + is_enabled = true;
  3932. + script_dict->SetBoolean(kScriptIsEnabled, is_enabled);
  3933. +}
  3934. +
  3935. +}
  3936. diff --git a/components/user_scripts/browser/user_script_prefs.h b/components/user_scripts/browser/user_script_prefs.h
  3937. new file mode 100644
  3938. --- /dev/null
  3939. +++ b/components/user_scripts/browser/user_script_prefs.h
  3940. @@ -0,0 +1,62 @@
  3941. +/*
  3942. + This file is part of Bromite.
  3943. +
  3944. + Bromite is free software: you can redistribute it and/or modify
  3945. + it under the terms of the GNU General Public License as published by
  3946. + the Free Software Foundation, either version 3 of the License, or
  3947. + (at your option) any later version.
  3948. +
  3949. + Bromite is distributed in the hope that it will be useful,
  3950. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  3951. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3952. + GNU General Public License for more details.
  3953. +
  3954. + You should have received a copy of the GNU General Public License
  3955. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  3956. +*/
  3957. +
  3958. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3959. +#define USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  3960. +
  3961. +#include "content/public/browser/browser_context.h"
  3962. +#include "components/prefs/pref_service.h"
  3963. +#include "components/pref_registry/pref_registry_syncable.h"
  3964. +
  3965. +#include "user_script_pref_info.h"
  3966. +#include "../common/user_script.h"
  3967. +
  3968. +namespace user_scripts {
  3969. +
  3970. +namespace prefs {
  3971. + extern const char kUserScriptsEnabled[];
  3972. +}
  3973. +
  3974. +class UserScriptsPrefs {
  3975. + public:
  3976. + UserScriptsPrefs(
  3977. + PrefService* prefs);
  3978. +
  3979. + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
  3980. +
  3981. + bool IsEnabled();
  3982. + void SetEnabled(bool enabled);
  3983. +
  3984. + void StartupTryout(int number);
  3985. + int GetCurrentStartupTryout();
  3986. +
  3987. + void CompareWithPrefs(UserScriptList& user_scripts);
  3988. +
  3989. + std::string GetScriptsInfo();
  3990. + void RemoveScriptFromPrefs(const std::string& script_id);
  3991. + void SetScriptEnabled(const std::string& script_id, bool is_enabled);
  3992. +
  3993. + std::unique_ptr<UserScriptsListPrefs::ScriptInfo> CreateScriptInfoFromPrefs(
  3994. + const std::string& script_id) const;
  3995. +
  3996. + private:
  3997. + PrefService* prefs_;
  3998. +};
  3999. +
  4000. +}
  4001. +
  4002. +#endif // USERSCRIPTS_BROWSER_USERSCRIPT_PREFS_H_
  4003. \ No newline at end of file
  4004. diff --git a/components/user_scripts/browser/userscripts_browser_client.cc b/components/user_scripts/browser/userscripts_browser_client.cc
  4005. new file mode 100755
  4006. --- /dev/null
  4007. +++ b/components/user_scripts/browser/userscripts_browser_client.cc
  4008. @@ -0,0 +1,78 @@
  4009. +/*
  4010. + This file is part of Bromite.
  4011. +
  4012. + Bromite is free software: you can redistribute it and/or modify
  4013. + it under the terms of the GNU General Public License as published by
  4014. + the Free Software Foundation, either version 3 of the License, or
  4015. + (at your option) any later version.
  4016. +
  4017. + Bromite is distributed in the hope that it will be useful,
  4018. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4019. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4020. + GNU General Public License for more details.
  4021. +
  4022. + You should have received a copy of the GNU General Public License
  4023. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4024. +*/
  4025. +
  4026. +#include "userscripts_browser_client.h"
  4027. +
  4028. +#include "base/logging.h"
  4029. +
  4030. +#include "chrome/browser/browser_process.h"
  4031. +
  4032. +#include "chrome/browser/profiles/profile.h"
  4033. +#include "chrome/browser/profiles/profile_manager.h"
  4034. +
  4035. +#include "../common/user_scripts_features.h"
  4036. +#include "user_script_loader.h"
  4037. +#include "file_task_runner.h"
  4038. +#include "user_script_prefs.h"
  4039. +
  4040. +namespace user_scripts {
  4041. +
  4042. +namespace {
  4043. +
  4044. +// remember: was ExtensionsBrowserClient
  4045. +UserScriptsBrowserClient* g_userscripts_browser_client = NULL;
  4046. +
  4047. +} // namespace
  4048. +
  4049. +UserScriptsBrowserClient::UserScriptsBrowserClient() {}
  4050. +
  4051. +UserScriptsBrowserClient::~UserScriptsBrowserClient() = default;
  4052. +
  4053. +// static
  4054. +UserScriptsBrowserClient* UserScriptsBrowserClient::GetInstance() {
  4055. + // only for browser process
  4056. + if (!g_browser_process)
  4057. + return NULL;
  4058. +
  4059. + // singleton
  4060. + if (g_userscripts_browser_client)
  4061. + return g_userscripts_browser_client;
  4062. +
  4063. + // make file task runner
  4064. + GetUserScriptsFileTaskRunner().get();
  4065. +
  4066. + // new instance singleton
  4067. + g_userscripts_browser_client = new UserScriptsBrowserClient();
  4068. +
  4069. + return g_userscripts_browser_client;
  4070. +}
  4071. +
  4072. +void UserScriptsBrowserClient::SetProfile(content::BrowserContext* context) {
  4073. + browser_context_ = context;
  4074. +
  4075. + prefs_ =
  4076. + std::make_unique<user_scripts::UserScriptsPrefs>(
  4077. + static_cast<Profile*>(context)->GetPrefs());
  4078. +
  4079. + userscript_loader_ =
  4080. + std::make_unique<user_scripts::UserScriptLoader>(browser_context_, prefs_.get());
  4081. + if (prefs_->IsEnabled()) {
  4082. + userscript_loader_->SetReady(true);
  4083. + }
  4084. +}
  4085. +
  4086. +} // namespace user_scripts
  4087. diff --git a/components/user_scripts/browser/userscripts_browser_client.h b/components/user_scripts/browser/userscripts_browser_client.h
  4088. new file mode 100755
  4089. --- /dev/null
  4090. +++ b/components/user_scripts/browser/userscripts_browser_client.h
  4091. @@ -0,0 +1,62 @@
  4092. +/*
  4093. + This file is part of Bromite.
  4094. +
  4095. + Bromite is free software: you can redistribute it and/or modify
  4096. + it under the terms of the GNU General Public License as published by
  4097. + the Free Software Foundation, either version 3 of the License, or
  4098. + (at your option) any later version.
  4099. +
  4100. + Bromite is distributed in the hope that it will be useful,
  4101. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  4102. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  4103. + GNU General Public License for more details.
  4104. +
  4105. + You should have received a copy of the GNU General Public License
  4106. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  4107. +*/
  4108. +
  4109. +#ifndef USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4110. +#define USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4111. +
  4112. +#include <memory>
  4113. +#include <string>
  4114. +#include <vector>
  4115. +
  4116. +#include "content/public/browser/browser_context.h"
  4117. +
  4118. +#include "../common/user_script.h"
  4119. +#include "user_script_loader.h"
  4120. +#include "user_script_prefs.h"
  4121. +
  4122. +namespace user_scripts {
  4123. +
  4124. +class UserScriptsBrowserClient {
  4125. + public:
  4126. + UserScriptsBrowserClient();
  4127. + UserScriptsBrowserClient(const UserScriptsBrowserClient&) = delete;
  4128. + UserScriptsBrowserClient& operator=(const UserScriptsBrowserClient&) = delete;
  4129. + virtual ~UserScriptsBrowserClient();
  4130. +
  4131. + // Returns the single instance of |this|.
  4132. + static UserScriptsBrowserClient* GetInstance();
  4133. +
  4134. + void SetProfile(content::BrowserContext* context);
  4135. +
  4136. + user_scripts::UserScriptsPrefs* GetPrefs() {
  4137. + return prefs_.get();
  4138. + }
  4139. +
  4140. + user_scripts::UserScriptLoader* GetLoader() {
  4141. + return userscript_loader_.get();
  4142. + }
  4143. +
  4144. + private:
  4145. + std::unique_ptr<UserScriptList> scripts_;
  4146. + content::BrowserContext* browser_context_;
  4147. + std::unique_ptr<user_scripts::UserScriptsPrefs> prefs_;
  4148. + std::unique_ptr<user_scripts::UserScriptLoader> userscript_loader_;
  4149. +};
  4150. +
  4151. +} // namespace extensions
  4152. +
  4153. +#endif // USERSCRIPTS_BROWSER_USERSCRIPTS_BROWSER_CLIENT_H_
  4154. diff --git a/components/user_scripts/common/BUILD.gn b/components/user_scripts/common/BUILD.gn
  4155. new file mode 100755
  4156. --- /dev/null
  4157. +++ b/components/user_scripts/common/BUILD.gn
  4158. @@ -0,0 +1,52 @@
  4159. +# Copyright 2014 The Chromium Authors. All rights reserved.
  4160. +# Use of this source code is governed by a BSD-style license that can be
  4161. +# found in the LICENSE file.
  4162. +
  4163. +import("//build/config/features.gni")
  4164. +import("//mojo/public/tools/bindings/mojom.gni")
  4165. +
  4166. +static_library("common") {
  4167. + sources = [
  4168. + "user_scripts_features.cc",
  4169. + "user_scripts_features.h",
  4170. + "constants.h",
  4171. + "host_id.cc",
  4172. + "host_id.h",
  4173. + "script_constants.h",
  4174. + "url_pattern_set.cc",
  4175. + "url_pattern_set.h",
  4176. + "url_pattern.cc",
  4177. + "url_pattern.h",
  4178. + "user_script.cc",
  4179. + "user_script.h",
  4180. + "view_type.cc",
  4181. + "view_type.h",
  4182. + "extension_messages.cc",
  4183. + "extension_messages.h",
  4184. + "extension_message_generator.cc",
  4185. + "extension_message_generator.h",
  4186. + ]
  4187. +
  4188. + configs += [
  4189. + "//build/config:precompiled_headers",
  4190. +
  4191. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
  4192. + "//build/config/compiler:no_size_t_to_int_warning",
  4193. + "//build/config/compiler:wexit_time_destructors",
  4194. + ]
  4195. +
  4196. + public_deps = [
  4197. + "//components/services/app_service/public/cpp:app_file_handling",
  4198. + "//content/public/common",
  4199. + "//ipc",
  4200. + "//skia",
  4201. + ]
  4202. +
  4203. + deps = [
  4204. + "//base",
  4205. + "//components/url_formatter",
  4206. + "//components/url_matcher",
  4207. + "//components/version_info",
  4208. + "//crypto",
  4209. + ]
  4210. +}
  4211. diff --git a/components/user_scripts/common/constants.h b/components/user_scripts/common/constants.h
  4212. new file mode 100755
  4213. --- /dev/null
  4214. +++ b/components/user_scripts/common/constants.h
  4215. @@ -0,0 +1,21 @@
  4216. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4217. +// Use of this source code is governed by a BSD-style license that can be
  4218. +// found in the LICENSE file.
  4219. +
  4220. +#ifndef USERSCRIPTS_COMMON_CONSTANTS_H_
  4221. +#define USERSCRIPTS_COMMON_CONSTANTS_H_
  4222. +
  4223. +#include "base/files/file_path.h"
  4224. +#include "base/strings/string_piece_forward.h"
  4225. +#include "components/services/app_service/public/mojom/types.mojom.h"
  4226. +#include "components/version_info/channel.h"
  4227. +#include "ui/base/layout.h"
  4228. +
  4229. +namespace user_scripts {
  4230. +
  4231. +// The origin of injected CSS.
  4232. +enum CSSOrigin { /*CSS_ORIGIN_AUTHOR,*/ CSS_ORIGIN_USER };
  4233. +
  4234. +} // namespace user_scripts
  4235. +
  4236. +#endif // USERSCRIPTS_COMMON_CONSTANTS_H_
  4237. diff --git a/components/user_scripts/common/error_utils.cc b/components/user_scripts/common/error_utils.cc
  4238. new file mode 100755
  4239. --- /dev/null
  4240. +++ b/components/user_scripts/common/error_utils.cc
  4241. @@ -0,0 +1,54 @@
  4242. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4243. +// Use of this source code is governed by a BSD-style license that can be
  4244. +// found in the LICENSE file.
  4245. +
  4246. +#include "error_utils.h"
  4247. +
  4248. +#include <initializer_list>
  4249. +
  4250. +#include "base/check_op.h"
  4251. +#include "base/strings/string_tokenizer.h"
  4252. +#include "base/strings/string_util.h"
  4253. +#include "base/strings/utf_string_conversions.h"
  4254. +
  4255. +namespace user_scripts {
  4256. +
  4257. +namespace {
  4258. +
  4259. +std::string FormatErrorMessageInternal(
  4260. + base::StringPiece format,
  4261. + std::initializer_list<base::StringPiece> args) {
  4262. + std::string format_str = format.as_string();
  4263. + base::StringTokenizer tokenizer(format_str, "*");
  4264. + tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
  4265. +
  4266. + std::vector<base::StringPiece> result_pieces;
  4267. + auto* args_it = args.begin();
  4268. + while (tokenizer.GetNext()) {
  4269. + if (!tokenizer.token_is_delim()) {
  4270. + result_pieces.push_back(tokenizer.token_piece());
  4271. + continue;
  4272. + }
  4273. +
  4274. + CHECK_NE(args_it, args.end())
  4275. + << "More placeholders (*) than substitutions.";
  4276. +
  4277. + // Substitute the argument.
  4278. + result_pieces.push_back(*args_it);
  4279. + args_it++;
  4280. + }
  4281. +
  4282. + // Not all substitutions were consumed.
  4283. + CHECK_EQ(args_it, args.end()) << "Fewer placeholders (*) than substitutions.";
  4284. +
  4285. + return base::JoinString(result_pieces, "" /* separator */);
  4286. +}
  4287. +
  4288. +} // namespace
  4289. +
  4290. +std::string ErrorUtils::FormatErrorMessage(base::StringPiece format,
  4291. + base::StringPiece s1) {
  4292. + return FormatErrorMessageInternal(format, {s1});
  4293. +}
  4294. +
  4295. +} // namespace user_scripts
  4296. diff --git a/components/user_scripts/common/error_utils.h b/components/user_scripts/common/error_utils.h
  4297. new file mode 100755
  4298. --- /dev/null
  4299. +++ b/components/user_scripts/common/error_utils.h
  4300. @@ -0,0 +1,24 @@
  4301. +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
  4302. +// Use of this source code is governed by a BSD-style license that can be
  4303. +// found in the LICENSE file.
  4304. +
  4305. +#ifndef USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4306. +#define USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4307. +
  4308. +#include <string>
  4309. +
  4310. +#include "base/strings/string_piece.h"
  4311. +
  4312. +namespace user_scripts {
  4313. +
  4314. +class ErrorUtils {
  4315. + public:
  4316. + // Creates an error messages from a pattern.
  4317. + static std::string FormatErrorMessage(base::StringPiece format,
  4318. + base::StringPiece s1);
  4319. +
  4320. +};
  4321. +
  4322. +} // namespace extensions
  4323. +
  4324. +#endif // USERSCRIPTS_COMMON_ERROR_UTILS_H_
  4325. diff --git a/components/user_scripts/common/extension_message_generator.cc b/components/user_scripts/common/extension_message_generator.cc
  4326. new file mode 100755
  4327. --- /dev/null
  4328. +++ b/components/user_scripts/common/extension_message_generator.cc
  4329. @@ -0,0 +1,29 @@
  4330. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4331. +// Use of this source code is governed by a BSD-style license that can be
  4332. +// found in the LICENSE file.
  4333. +
  4334. +// Get basic type definitions.
  4335. +#define IPC_MESSAGE_IMPL
  4336. +#include "components/user_scripts/common/extension_message_generator.h"
  4337. +
  4338. +// Generate constructors.
  4339. +#include "ipc/struct_constructor_macros.h"
  4340. +#include "components/user_scripts/common/extension_message_generator.h"
  4341. +
  4342. +// Generate param traits write methods.
  4343. +#include "ipc/param_traits_write_macros.h"
  4344. +namespace IPC {
  4345. +#include "components/user_scripts/common/extension_message_generator.h"
  4346. +} // namespace IPC
  4347. +
  4348. +// Generate param traits read methods.
  4349. +#include "ipc/param_traits_read_macros.h"
  4350. +namespace IPC {
  4351. +#include "components/user_scripts/common/extension_message_generator.h"
  4352. +} // namespace IPC
  4353. +
  4354. +// Generate param traits log methods.
  4355. +#include "ipc/param_traits_log_macros.h"
  4356. +namespace IPC {
  4357. +#include "components/user_scripts/common/extension_message_generator.h"
  4358. +} // namespace IPC
  4359. diff --git a/components/user_scripts/common/extension_message_generator.h b/components/user_scripts/common/extension_message_generator.h
  4360. new file mode 100755
  4361. --- /dev/null
  4362. +++ b/components/user_scripts/common/extension_message_generator.h
  4363. @@ -0,0 +1,11 @@
  4364. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4365. +// Use of this source code is governed by a BSD-style license that can be
  4366. +// found in the LICENSE file.
  4367. +
  4368. +// Multiply-included file, hence no include guard.
  4369. +
  4370. +#undef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4371. +#include "extension_messages.h"
  4372. +#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4373. +#error "Failed to include header extension_messages.h"
  4374. +#endif
  4375. diff --git a/components/user_scripts/common/extension_messages.cc b/components/user_scripts/common/extension_messages.cc
  4376. new file mode 100755
  4377. --- /dev/null
  4378. +++ b/components/user_scripts/common/extension_messages.cc
  4379. @@ -0,0 +1,40 @@
  4380. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4381. +// Use of this source code is governed by a BSD-style license that can be
  4382. +// found in the LICENSE file.
  4383. +
  4384. +#include "extension_messages.h"
  4385. +
  4386. +#include <stddef.h>
  4387. +
  4388. +#include <memory>
  4389. +#include <utility>
  4390. +
  4391. +#include "content/public/common/common_param_traits.h"
  4392. +
  4393. +namespace IPC {
  4394. +
  4395. +void ParamTraits<HostID>::Write(base::Pickle* m, const param_type& p) {
  4396. + WriteParam(m, p.type());
  4397. + WriteParam(m, p.id());
  4398. +}
  4399. +
  4400. +bool ParamTraits<HostID>::Read(const base::Pickle* m,
  4401. + base::PickleIterator* iter,
  4402. + param_type* r) {
  4403. + HostID::HostType type;
  4404. + std::string id;
  4405. + if (!ReadParam(m, iter, &type))
  4406. + return false;
  4407. + if (!ReadParam(m, iter, &id))
  4408. + return false;
  4409. + *r = HostID(type, id);
  4410. + return true;
  4411. +}
  4412. +
  4413. +void ParamTraits<HostID>::Log(
  4414. + const param_type& p, std::string* l) {
  4415. + LogParam(p.type(), l);
  4416. + LogParam(p.id(), l);
  4417. +}
  4418. +
  4419. +} // namespace IPC
  4420. diff --git a/components/user_scripts/common/extension_messages.h b/components/user_scripts/common/extension_messages.h
  4421. new file mode 100755
  4422. --- /dev/null
  4423. +++ b/components/user_scripts/common/extension_messages.h
  4424. @@ -0,0 +1,70 @@
  4425. +// Copyright 2014 The Chromium Authors. All rights reserved.
  4426. +// Use of this source code is governed by a BSD-style license that can be
  4427. +// found in the LICENSE file.
  4428. +
  4429. +// IPC messages for extensions.
  4430. +
  4431. +#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4432. +#define EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4433. +
  4434. +#include <stdint.h>
  4435. +
  4436. +#include <map>
  4437. +#include <memory>
  4438. +#include <set>
  4439. +#include <string>
  4440. +#include <vector>
  4441. +
  4442. +#include "base/macros.h"
  4443. +#include "base/memory/read_only_shared_memory_region.h"
  4444. +#include "base/values.h"
  4445. +#include "content/public/common/common_param_traits.h"
  4446. +#include "constants.h"
  4447. +#include "host_id.h"
  4448. +#include "ipc/ipc_message_macros.h"
  4449. +#include "url/gurl.h"
  4450. +#include "url/origin.h"
  4451. +
  4452. +#define IPC_MESSAGE_START ExtensionMsgStart
  4453. +
  4454. +IPC_ENUM_TRAITS_MAX_VALUE(HostID::HostType, HostID::HOST_TYPE_LAST)
  4455. +
  4456. +// Singly-included section for custom IPC traits.
  4457. +#ifndef INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4458. +#define INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4459. +
  4460. +namespace IPC {
  4461. +
  4462. +template <>
  4463. +struct ParamTraits<HostID> {
  4464. + typedef HostID param_type;
  4465. + static void Write(base::Pickle* m, const param_type& p);
  4466. + static bool Read(const base::Pickle* m,
  4467. + base::PickleIterator* iter,
  4468. + param_type* r);
  4469. + static void Log(const param_type& p, std::string* l);
  4470. +};
  4471. +
  4472. +
  4473. +} // namespace IPC
  4474. +
  4475. +#endif // INTERNAL_EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4476. +
  4477. +// Notification that the user scripts have been updated. It has one
  4478. +// ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
  4479. +// This memory region is valid in the context of the renderer.
  4480. +// If |owner| is not empty, then the shared memory handle refers to |owner|'s
  4481. +// programmatically-defined scripts. Otherwise, the handle refers to all
  4482. +// hosts' statically defined scripts. So far, only extension-hosts support
  4483. +// statically defined scripts; WebUI-hosts don't.
  4484. +// If |changed_hosts| is not empty, only the host in that set will
  4485. +// be updated. Otherwise, all hosts that have scripts in the shared memory
  4486. +// region will be updated. Note that the empty set => all hosts case is not
  4487. +// supported for per-extension programmatically-defined script regions; in such
  4488. +// regions, the owner is expected to list itself as the only changed host.
  4489. +// If |whitelisted_only| is true, this process should only run whitelisted
  4490. +// scripts and not all user scripts.
  4491. +IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
  4492. + base::ReadOnlySharedMemoryRegion)
  4493. +
  4494. +#endif // EXTENSIONS_COMMON_EXTENSION_MESSAGES_H_
  4495. diff --git a/components/user_scripts/common/host_id.cc b/components/user_scripts/common/host_id.cc
  4496. new file mode 100755
  4497. --- /dev/null
  4498. +++ b/components/user_scripts/common/host_id.cc
  4499. @@ -0,0 +1,31 @@
  4500. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4501. +// Use of this source code is governed by a BSD-style license that can be
  4502. +// found in the LICENSE file.
  4503. +
  4504. +#include "host_id.h"
  4505. +
  4506. +#include <tuple>
  4507. +
  4508. +HostID::HostID()
  4509. + : type_(HostType::EXTENSIONS) {
  4510. +}
  4511. +
  4512. +HostID::HostID(HostType type, const std::string& id)
  4513. + : type_(type), id_(id) {
  4514. +}
  4515. +
  4516. +HostID::HostID(const HostID& host_id)
  4517. + : type_(host_id.type()),
  4518. + id_(host_id.id()) {
  4519. +}
  4520. +
  4521. +HostID::~HostID() {
  4522. +}
  4523. +
  4524. +bool HostID::operator<(const HostID& host_id) const {
  4525. + return std::tie(type_, id_) < std::tie(host_id.type_, host_id.id_);
  4526. +}
  4527. +
  4528. +bool HostID::operator==(const HostID& host_id) const {
  4529. + return type_ == host_id.type_ && id_ == host_id.id_;
  4530. +}
  4531. diff --git a/components/user_scripts/common/host_id.h b/components/user_scripts/common/host_id.h
  4532. new file mode 100755
  4533. --- /dev/null
  4534. +++ b/components/user_scripts/common/host_id.h
  4535. @@ -0,0 +1,35 @@
  4536. +// Copyright 2015 The Chromium Authors. All rights reserved.
  4537. +// Use of this source code is governed by a BSD-style license that can be
  4538. +// found in the LICENSE file.
  4539. +
  4540. +#ifndef USERSCRIPTS_COMMON_HOST_ID_H_
  4541. +#define USERSCRIPTS_COMMON_HOST_ID_H_
  4542. +
  4543. +#include <string>
  4544. +
  4545. +// IDs of hosts who own user scripts.
  4546. +// A HostID is immutable after creation.
  4547. +struct HostID {
  4548. + enum HostType { EXTENSIONS, WEBUI, HOST_TYPE_LAST = WEBUI };
  4549. +
  4550. + HostID();
  4551. + HostID(HostType type, const std::string& id);
  4552. + HostID(const HostID& host_id);
  4553. + ~HostID();
  4554. +
  4555. + bool operator<(const HostID& host_id) const;
  4556. + bool operator==(const HostID& host_id) const;
  4557. +
  4558. + HostType type() const { return type_; }
  4559. + const std::string& id() const { return id_; }
  4560. +
  4561. + private:
  4562. + // The type of the host.
  4563. + HostType type_;
  4564. +
  4565. + // Similar to extension_id, host_id is a unique indentifier for a host,
  4566. + // e.g., an Extension or WebUI.
  4567. + std::string id_;
  4568. +};
  4569. +
  4570. +#endif // USERSCRIPTS_COMMON_HOST_ID_H_
  4571. diff --git a/components/user_scripts/common/script_constants.h b/components/user_scripts/common/script_constants.h
  4572. new file mode 100755
  4573. --- /dev/null
  4574. +++ b/components/user_scripts/common/script_constants.h
  4575. @@ -0,0 +1,33 @@
  4576. +// Copyright 2020 The Chromium Authors. All rights reserved.
  4577. +// Use of this source code is governed by a BSD-style license that can be
  4578. +// found in the LICENSE file.
  4579. +
  4580. +#ifndef USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4581. +#define USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4582. +
  4583. +namespace user_scripts {
  4584. +
  4585. +// Whether to fall back to matching the origin for frames where the URL
  4586. +// cannot be matched directly, such as those with about: or data: schemes.
  4587. +enum class MatchOriginAsFallbackBehavior {
  4588. + // Never fall back on the origin; this means scripts will never match on
  4589. + // these frames.
  4590. + kNever,
  4591. + // Match the origin only for about:-scheme frames, and then climb the frame
  4592. + // tree to find an appropriate ancestor to get a full URL (including path).
  4593. + // This is for supporting the "match_about_blank" key.
  4594. + // TODO(devlin): I wonder if we could simplify this to be "MatchForAbout",
  4595. + // and not worry about climbing the frame tree. It would be a behavior
  4596. + // change, but I wonder how many extensions it would impact in practice.
  4597. + kMatchForAboutSchemeAndClimbTree,
  4598. + // Match the origin as a fallback whenever applicable. This won't have a
  4599. + // corresponding path.
  4600. + kAlways,
  4601. +};
  4602. +
  4603. +// TODO(devlin): Move the other non-UserScript-specific constants like
  4604. +// RunLocation and InjectionType from UserScript into here.
  4605. +
  4606. +}
  4607. +
  4608. +#endif // USERSCRIPTS_COMMON_SCRIPT_CONSTANTS_H_
  4609. diff --git a/components/user_scripts/common/url_pattern.cc b/components/user_scripts/common/url_pattern.cc
  4610. new file mode 100755
  4611. --- /dev/null
  4612. +++ b/components/user_scripts/common/url_pattern.cc
  4613. @@ -0,0 +1,807 @@
  4614. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  4615. +// Use of this source code is governed by a BSD-style license that can be
  4616. +// found in the LICENSE file.
  4617. +
  4618. +#include "url_pattern.h"
  4619. +
  4620. +#include <stddef.h>
  4621. +
  4622. +#include <ostream>
  4623. +
  4624. +#include "base/logging.h"
  4625. +#include "base/stl_util.h"
  4626. +#include "base/strings/pattern.h"
  4627. +#include "base/strings/strcat.h"
  4628. +#include "base/strings/string_number_conversions.h"
  4629. +#include "base/strings/string_split.h"
  4630. +#include "base/strings/string_util.h"
  4631. +#include "base/strings/stringprintf.h"
  4632. +#include "content/public/common/url_constants.h"
  4633. +#include "constants.h"
  4634. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  4635. +#include "net/base/url_util.h"
  4636. +#include "url/gurl.h"
  4637. +#include "url/url_util.h"
  4638. +
  4639. +const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
  4640. +
  4641. +namespace {
  4642. +
  4643. +// TODO(aa): What about more obscure schemes like javascript: ?
  4644. +// Note: keep this array in sync with kValidSchemeMasks.
  4645. +const char* const kValidSchemes[] = {
  4646. + url::kHttpScheme, url::kHttpsScheme,
  4647. + url::kFileScheme, url::kFtpScheme,
  4648. + /*content::kChromeUIScheme,*/ /*extensions::kExtensionScheme,*/
  4649. + url::kFileSystemScheme, url::kWsScheme,
  4650. + url::kWssScheme, url::kDataScheme,
  4651. +};
  4652. +
  4653. +const int kValidSchemeMasks[] = {
  4654. + URLPattern::SCHEME_HTTP, URLPattern::SCHEME_HTTPS,
  4655. + URLPattern::SCHEME_FILE, URLPattern::SCHEME_FTP,
  4656. + /*URLPattern::SCHEME_CHROMEUI,*/ /*URLPattern::SCHEME_EXTENSION,*/
  4657. + URLPattern::SCHEME_FILESYSTEM, URLPattern::SCHEME_WS,
  4658. + URLPattern::SCHEME_WSS, URLPattern::SCHEME_DATA,
  4659. +};
  4660. +
  4661. +static_assert(base::size(kValidSchemes) == base::size(kValidSchemeMasks),
  4662. + "must keep these arrays in sync");
  4663. +
  4664. +const char kParseSuccess[] = "Success.";
  4665. +const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
  4666. +const char kParseErrorInvalidScheme[] = "Invalid scheme.";
  4667. +const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
  4668. +const char kParseErrorEmptyHost[] = "Host can not be empty.";
  4669. +const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
  4670. +const char kParseErrorEmptyPath[] = "Empty path.";
  4671. +const char kParseErrorInvalidPort[] = "Invalid port.";
  4672. +const char kParseErrorInvalidHost[] = "Invalid host.";
  4673. +
  4674. +// Message explaining each URLPattern::ParseResult.
  4675. +const char* const kParseResultMessages[] = {
  4676. + kParseSuccess,
  4677. + kParseErrorMissingSchemeSeparator,
  4678. + kParseErrorInvalidScheme,
  4679. + kParseErrorWrongSchemeType,
  4680. + kParseErrorEmptyHost,
  4681. + kParseErrorInvalidHostWildcard,
  4682. + kParseErrorEmptyPath,
  4683. + kParseErrorInvalidPort,
  4684. + kParseErrorInvalidHost,
  4685. +};
  4686. +
  4687. +static_assert(static_cast<int>(URLPattern::ParseResult::kNumParseResults) ==
  4688. + base::size(kParseResultMessages),
  4689. + "must add message for each parse result");
  4690. +
  4691. +const char kPathSeparator[] = "/";
  4692. +
  4693. +bool IsStandardScheme(base::StringPiece scheme) {
  4694. + // "*" gets the same treatment as a standard scheme.
  4695. + if (scheme == "*")
  4696. + return true;
  4697. +
  4698. + return url::IsStandard(scheme.data(),
  4699. + url::Component(0, static_cast<int>(scheme.length())));
  4700. +}
  4701. +
  4702. +bool IsValidPortForScheme(base::StringPiece scheme, base::StringPiece port) {
  4703. + if (port == "*")
  4704. + return true;
  4705. +
  4706. + // Only accept non-wildcard ports if the scheme uses ports.
  4707. + if (url::DefaultPortForScheme(scheme.data(), scheme.length()) ==
  4708. + url::PORT_UNSPECIFIED) {
  4709. + return false;
  4710. + }
  4711. +
  4712. + int parsed_port = url::PORT_UNSPECIFIED;
  4713. + if (!base::StringToInt(port, &parsed_port))
  4714. + return false;
  4715. + return (parsed_port >= 0) && (parsed_port < 65536);
  4716. +}
  4717. +
  4718. +// Returns |path| with the trailing wildcard stripped if one existed.
  4719. +//
  4720. +// The functions that rely on this (OverlapsWith and Contains) are only
  4721. +// called for the patterns inside URLPatternSet. In those cases, we know that
  4722. +// the path will have only a single wildcard at the end. This makes figuring
  4723. +// out overlap much easier. It seems like there is probably a computer-sciency
  4724. +// way to solve the general case, but we don't need that yet.
  4725. +base::StringPiece StripTrailingWildcard(base::StringPiece path) {
  4726. + if (base::EndsWith(path, "*"))
  4727. + path.remove_suffix(1);
  4728. + return path;
  4729. +}
  4730. +
  4731. +// Removes trailing dot from |host_piece| if any.
  4732. +base::StringPiece CanonicalizeHostForMatching(base::StringPiece host_piece) {
  4733. + if (base::EndsWith(host_piece, "."))
  4734. + host_piece.remove_suffix(1);
  4735. + return host_piece;
  4736. +}
  4737. +
  4738. +} // namespace
  4739. +
  4740. +// static
  4741. +bool URLPattern::IsValidSchemeForExtensions(base::StringPiece scheme) {
  4742. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  4743. + if (scheme == kValidSchemes[i])
  4744. + return true;
  4745. + }
  4746. + return false;
  4747. +}
  4748. +
  4749. +// static
  4750. +int URLPattern::GetValidSchemeMaskForExtensions() {
  4751. + int result = 0;
  4752. + for (size_t i = 0; i < base::size(kValidSchemeMasks); ++i)
  4753. + result |= kValidSchemeMasks[i];
  4754. + return result;
  4755. +}
  4756. +
  4757. +URLPattern::URLPattern()
  4758. + : valid_schemes_(SCHEME_NONE),
  4759. + match_all_urls_(false),
  4760. + match_subdomains_(false),
  4761. + port_("*") {}
  4762. +
  4763. +URLPattern::URLPattern(int valid_schemes)
  4764. + : valid_schemes_(valid_schemes),
  4765. + match_all_urls_(false),
  4766. + match_subdomains_(false),
  4767. + port_("*") {}
  4768. +
  4769. +URLPattern::URLPattern(int valid_schemes, base::StringPiece pattern)
  4770. + // Strict error checking is used, because this constructor is only
  4771. + // appropriate when we know |pattern| is valid.
  4772. + : valid_schemes_(valid_schemes),
  4773. + match_all_urls_(false),
  4774. + match_subdomains_(false),
  4775. + port_("*") {
  4776. + ParseResult result = Parse(pattern);
  4777. + if (result != ParseResult::kSuccess) {
  4778. + const char* error_string = GetParseResultString(result);
  4779. + // Temporarily add more logging to investigate why this code path is
  4780. + // reached. For http://crbug.com/856948
  4781. + LOG(ERROR) << "Invalid pattern was given " << pattern << " result "
  4782. + << error_string;
  4783. + NOTREACHED() << "URLPattern invalid: '" << pattern
  4784. + << "'; error: " << error_string;
  4785. + }
  4786. +}
  4787. +
  4788. +URLPattern::URLPattern(const URLPattern& other) = default;
  4789. +
  4790. +URLPattern::URLPattern(URLPattern&& other) = default;
  4791. +
  4792. +URLPattern::~URLPattern() {
  4793. +}
  4794. +
  4795. +URLPattern& URLPattern::operator=(const URLPattern& other) = default;
  4796. +
  4797. +URLPattern& URLPattern::operator=(URLPattern&& other) = default;
  4798. +
  4799. +bool URLPattern::operator<(const URLPattern& other) const {
  4800. + return GetAsString() < other.GetAsString();
  4801. +}
  4802. +
  4803. +bool URLPattern::operator>(const URLPattern& other) const {
  4804. + return GetAsString() > other.GetAsString();
  4805. +}
  4806. +
  4807. +bool URLPattern::operator==(const URLPattern& other) const {
  4808. + return GetAsString() == other.GetAsString();
  4809. +}
  4810. +
  4811. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) {
  4812. + return out << '"' << url_pattern.GetAsString() << '"';
  4813. +}
  4814. +
  4815. +URLPattern::ParseResult URLPattern::Parse(base::StringPiece pattern) {
  4816. + spec_.clear();
  4817. + SetMatchAllURLs(false);
  4818. + SetMatchSubdomains(false);
  4819. + SetPort("*");
  4820. +
  4821. + // Special case pattern to match every valid URL.
  4822. + if (pattern == kAllUrlsPattern) {
  4823. + SetMatchAllURLs(true);
  4824. + return ParseResult::kSuccess;
  4825. + }
  4826. +
  4827. + // Parse out the scheme.
  4828. + size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator);
  4829. + bool has_standard_scheme_separator = true;
  4830. +
  4831. + // Some urls also use ':' alone as the scheme separator.
  4832. + if (scheme_end_pos == base::StringPiece::npos) {
  4833. + scheme_end_pos = pattern.find(':');
  4834. + has_standard_scheme_separator = false;
  4835. + }
  4836. +
  4837. + if (scheme_end_pos == base::StringPiece::npos)
  4838. + return ParseResult::kMissingSchemeSeparator;
  4839. +
  4840. + if (!SetScheme(pattern.substr(0, scheme_end_pos)))
  4841. + return ParseResult::kInvalidScheme;
  4842. +
  4843. + bool standard_scheme = IsStandardScheme(scheme_);
  4844. + if (standard_scheme != has_standard_scheme_separator)
  4845. + return ParseResult::kWrongSchemeSeparator;
  4846. +
  4847. + // Advance past the scheme separator.
  4848. + scheme_end_pos +=
  4849. + (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1);
  4850. + if (scheme_end_pos >= pattern.size())
  4851. + return ParseResult::kEmptyHost;
  4852. +
  4853. + // Parse out the host and path.
  4854. + size_t host_start_pos = scheme_end_pos;
  4855. + size_t path_start_pos = 0;
  4856. +
  4857. + if (!standard_scheme) {
  4858. + path_start_pos = host_start_pos;
  4859. + } else if (scheme_ == url::kFileScheme) {
  4860. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  4861. + if (host_end_pos == base::StringPiece::npos) {
  4862. + // Allow hostname omission.
  4863. + // e.g. file://* is interpreted as file:///*,
  4864. + // file://foo* is interpreted as file:///foo*.
  4865. + path_start_pos = host_start_pos - 1;
  4866. + } else {
  4867. + // Ignore hostname if scheme is file://.
  4868. + // e.g. file://localhost/foo is equal to file:///foo.
  4869. + path_start_pos = host_end_pos;
  4870. + }
  4871. + } else {
  4872. + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
  4873. +
  4874. + // Host is required.
  4875. + if (host_start_pos == host_end_pos)
  4876. + return ParseResult::kEmptyHost;
  4877. +
  4878. + if (host_end_pos == base::StringPiece::npos)
  4879. + return ParseResult::kEmptyPath;
  4880. +
  4881. + base::StringPiece host_and_port =
  4882. + pattern.substr(host_start_pos, host_end_pos - host_start_pos);
  4883. +
  4884. + size_t port_separator_pos = base::StringPiece::npos;
  4885. + if (host_and_port[0] != '[') {
  4886. + // Not IPv6 (either IPv4 or just a normal address).
  4887. + port_separator_pos = host_and_port.find(':');
  4888. + } else { // IPv6.
  4889. + size_t host_end_pos = host_and_port.find(']');
  4890. + if (host_end_pos == base::StringPiece::npos)
  4891. + return ParseResult::kInvalidHost;
  4892. + if (host_end_pos == 1)
  4893. + return ParseResult::kEmptyHost;
  4894. +
  4895. + if (host_end_pos < host_and_port.length() - 1) {
  4896. + // The host isn't the only component. Check for a port. This would
  4897. + // require a ':' to follow the closing ']' from the host.
  4898. + if (host_and_port[host_end_pos + 1] != ':')
  4899. + return ParseResult::kInvalidHost;
  4900. +
  4901. + port_separator_pos = host_end_pos + 1;
  4902. + }
  4903. + }
  4904. +
  4905. + if (port_separator_pos != base::StringPiece::npos &&
  4906. + !SetPort(host_and_port.substr(port_separator_pos + 1))) {
  4907. + return ParseResult::kInvalidPort;
  4908. + }
  4909. +
  4910. + // Note: this substr() will be the entire string if the port position
  4911. + // wasn't found.
  4912. + base::StringPiece host_piece = host_and_port.substr(0, port_separator_pos);
  4913. +
  4914. + if (host_piece.empty())
  4915. + return ParseResult::kEmptyHost;
  4916. +
  4917. + if (host_piece == "*") {
  4918. + match_subdomains_ = true;
  4919. + host_piece = base::StringPiece();
  4920. + } else if (base::StartsWith(host_piece, "*.")) {
  4921. + if (host_piece.length() == 2) {
  4922. + // We don't allow just '*.' as a host.
  4923. + return ParseResult::kEmptyHost;
  4924. + }
  4925. + match_subdomains_ = true;
  4926. + host_piece = host_piece.substr(2);
  4927. + }
  4928. +
  4929. + host_ = host_piece.as_string();
  4930. +
  4931. + path_start_pos = host_end_pos;
  4932. + }
  4933. +
  4934. + SetPath(pattern.substr(path_start_pos));
  4935. +
  4936. + // No other '*' can occur in the host, though. This isn't necessary, but is
  4937. + // done as a convenience to developers who might otherwise be confused and
  4938. + // think '*' works as a glob in the host.
  4939. + if (host_.find('*') != std::string::npos)
  4940. + return ParseResult::kInvalidHostWildcard;
  4941. +
  4942. + if (!host_.empty()) {
  4943. + // If |host_| is present (i.e., isn't a wildcard), we need to canonicalize
  4944. + // it.
  4945. + url::CanonHostInfo host_info;
  4946. + host_ = net::CanonicalizeHost(host_, &host_info);
  4947. + // net::CanonicalizeHost() returns an empty string on failure.
  4948. + if (host_.empty())
  4949. + return ParseResult::kInvalidHost;
  4950. + }
  4951. +
  4952. + // Null characters are not allowed in hosts.
  4953. + if (host_.find('\0') != std::string::npos)
  4954. + return ParseResult::kInvalidHost;
  4955. +
  4956. + return ParseResult::kSuccess;
  4957. +}
  4958. +
  4959. +void URLPattern::SetValidSchemes(int valid_schemes) {
  4960. + // TODO(devlin): Should we check that valid_schemes agrees with |scheme_|
  4961. + // here? Otherwise, valid_schemes_ and schemes_ may stop agreeing with each
  4962. + // other (e.g., in the case of `*://*/*`, where the scheme should only be
  4963. + // http or https).
  4964. + spec_.clear();
  4965. + valid_schemes_ = valid_schemes;
  4966. +}
  4967. +
  4968. +void URLPattern::SetHost(base::StringPiece host) {
  4969. + spec_.clear();
  4970. + host_.assign(host.data(), host.size());
  4971. +}
  4972. +
  4973. +void URLPattern::SetMatchAllURLs(bool val) {
  4974. + spec_.clear();
  4975. + match_all_urls_ = val;
  4976. +
  4977. + if (val) {
  4978. + match_subdomains_ = true;
  4979. + scheme_ = "*";
  4980. + host_.clear();
  4981. + SetPath("/*");
  4982. + }
  4983. +}
  4984. +
  4985. +void URLPattern::SetMatchSubdomains(bool val) {
  4986. + spec_.clear();
  4987. + match_subdomains_ = val;
  4988. +}
  4989. +
  4990. +bool URLPattern::SetScheme(base::StringPiece scheme) {
  4991. + spec_.clear();
  4992. + scheme_.assign(scheme.data(), scheme.size());
  4993. + if (scheme_ == "*") {
  4994. + valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
  4995. + } else if (!IsValidScheme(scheme_)) {
  4996. + return false;
  4997. + }
  4998. + return true;
  4999. +}
  5000. +
  5001. +bool URLPattern::IsValidScheme(base::StringPiece scheme) const {
  5002. + if (valid_schemes_ == SCHEME_ALL)
  5003. + return true;
  5004. +
  5005. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  5006. + if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
  5007. + return true;
  5008. + }
  5009. +
  5010. + return false;
  5011. +}
  5012. +
  5013. +void URLPattern::SetPath(base::StringPiece path) {
  5014. + spec_.clear();
  5015. + path_.assign(path.data(), path.size());
  5016. + path_escaped_ = path_;
  5017. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
  5018. + base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
  5019. +}
  5020. +
  5021. +bool URLPattern::SetPort(base::StringPiece port) {
  5022. + spec_.clear();
  5023. + if (IsValidPortForScheme(scheme_, port)) {
  5024. + port_.assign(port.data(), port.size());
  5025. + return true;
  5026. + }
  5027. + return false;
  5028. +}
  5029. +
  5030. +bool URLPattern::MatchesURL(const GURL& test) const {
  5031. + // Invalid URLs can never match.
  5032. + if (!test.is_valid())
  5033. + return false;
  5034. +
  5035. + const GURL* test_url = &test;
  5036. + bool has_inner_url = test.inner_url() != nullptr;
  5037. +
  5038. + if (has_inner_url) {
  5039. + if (!test.SchemeIsFileSystem())
  5040. + return false; // The only nested URLs we handle are filesystem URLs.
  5041. + test_url = test.inner_url();
  5042. + }
  5043. +
  5044. + // Ensure the scheme matches first, since <all_urls> may not match this URL if
  5045. + // the scheme is excluded.
  5046. + if (!MatchesScheme(test_url->scheme_piece()))
  5047. + return false;
  5048. +
  5049. + if (match_all_urls_)
  5050. + return true;
  5051. +
  5052. + // Unless |match_all_urls_| is true, the grammar only permits matching
  5053. + // URLs with nonempty paths.
  5054. + if (!test.has_path())
  5055. + return false;
  5056. +
  5057. + std::string path_for_request = test.PathForRequest();
  5058. + if (has_inner_url) {
  5059. + path_for_request = base::StringPrintf("%s%s", test_url->path_piece().data(),
  5060. + path_for_request.c_str());
  5061. + }
  5062. +
  5063. + return MatchesSecurityOriginHelper(*test_url) &&
  5064. + MatchesPath(path_for_request);
  5065. +}
  5066. +
  5067. +bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
  5068. + const GURL* test_url = &test;
  5069. + bool has_inner_url = test.inner_url() != NULL;
  5070. +
  5071. + if (has_inner_url) {
  5072. + if (!test.SchemeIsFileSystem())
  5073. + return false; // The only nested URLs we handle are filesystem URLs.
  5074. + test_url = test.inner_url();
  5075. + }
  5076. +
  5077. + if (!MatchesScheme(test_url->scheme()))
  5078. + return false;
  5079. +
  5080. + if (match_all_urls_)
  5081. + return true;
  5082. +
  5083. + return MatchesSecurityOriginHelper(*test_url);
  5084. +}
  5085. +
  5086. +bool URLPattern::MatchesScheme(base::StringPiece test) const {
  5087. + if (!IsValidScheme(test))
  5088. + return false;
  5089. +
  5090. + return scheme_ == "*" || test == scheme_;
  5091. +}
  5092. +
  5093. +bool URLPattern::MatchesHost(base::StringPiece host) const {
  5094. + // TODO(devlin): This is a bit sad. Parsing urls is expensive. However, it's
  5095. + // important that we do this conversion to a GURL in order to canonicalize the
  5096. + // host (the pattern's host_ already is canonicalized from Parse()). We can't
  5097. + // just do string comparison.
  5098. + return MatchesHost(
  5099. + GURL(base::StringPrintf("%s%s%s/", url::kHttpScheme,
  5100. + url::kStandardSchemeSeparator, host.data())));
  5101. +}
  5102. +
  5103. +bool URLPattern::MatchesHost(const GURL& test) const {
  5104. + base::StringPiece test_host(CanonicalizeHostForMatching(test.host_piece()));
  5105. + const base::StringPiece pattern_host(CanonicalizeHostForMatching(host_));
  5106. +
  5107. + // If the hosts are exactly equal, we have a match.
  5108. + if (test_host == pattern_host)
  5109. + return true;
  5110. +
  5111. + // If we're matching subdomains, and we have no host in the match pattern,
  5112. + // that means that we're matching all hosts, which means we have a match no
  5113. + // matter what the test host is.
  5114. + if (match_subdomains_ && pattern_host.empty())
  5115. + return true;
  5116. +
  5117. + // Otherwise, we can only match if our match pattern matches subdomains.
  5118. + if (!match_subdomains_)
  5119. + return false;
  5120. +
  5121. + // We don't do subdomain matching against IP addresses, so we can give up now
  5122. + // if the test host is an IP address.
  5123. + if (test.HostIsIPAddress())
  5124. + return false;
  5125. +
  5126. + // Check if the test host is a subdomain of our host.
  5127. + if (test_host.length() <= (pattern_host.length() + 1))
  5128. + return false;
  5129. +
  5130. + if (!base::EndsWith(test_host, pattern_host))
  5131. + return false;
  5132. +
  5133. + return test_host[test_host.length() - pattern_host.length() - 1] == '.';
  5134. +}
  5135. +
  5136. +bool URLPattern::MatchesEffectiveTld(
  5137. + net::registry_controlled_domains::PrivateRegistryFilter private_filter,
  5138. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter)
  5139. + const {
  5140. + // Check if it matches all urls or is a pattern like http://*/*.
  5141. + if (match_all_urls_ || (match_subdomains_ && host_.empty()))
  5142. + return true;
  5143. +
  5144. + // If this doesn't even match subdomains, it can't possibly be a TLD wildcard.
  5145. + if (!match_subdomains_)
  5146. + return false;
  5147. +
  5148. + // If there was more than just a TLD in the host (e.g., *.foobar.com), it
  5149. + // doesn't match all hosts in an effective TLD.
  5150. + if (net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5151. + host_, unknown_filter, private_filter)) {
  5152. + return false;
  5153. + }
  5154. +
  5155. + // At this point the host could either be just a TLD ("com") or some unknown
  5156. + // TLD-like string ("notatld"). To disambiguate between them construct a
  5157. + // fake URL, and check the registry.
  5158. + //
  5159. + // If we recognized this TLD, then this is a pattern like *.com, and it
  5160. + // matches an effective TLD.
  5161. + return net::registry_controlled_domains::HostHasRegistryControlledDomain(
  5162. + "notatld." + host_, unknown_filter, private_filter);
  5163. +}
  5164. +
  5165. +bool URLPattern::MatchesSingleOrigin() const {
  5166. + // Strictly speaking, the port is part of the origin, but in URLPattern it
  5167. + // defaults to *. It's not very interesting anyway, so leave it out.
  5168. + return !MatchesEffectiveTld() && scheme_ != "*" && !match_subdomains_;
  5169. +}
  5170. +
  5171. +bool URLPattern::MatchesPath(base::StringPiece test) const {
  5172. + // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
  5173. + // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
  5174. + // The below if is a no-copy way of doing (test + "/*" == path_escaped_).
  5175. + if (path_escaped_.length() == test.length() + 2 &&
  5176. + base::StartsWith(path_escaped_.c_str(), test) &&
  5177. + base::EndsWith(path_escaped_, "/*")) {
  5178. + return true;
  5179. + }
  5180. +
  5181. + return base::MatchPattern(test, path_escaped_);
  5182. +}
  5183. +
  5184. +const std::string& URLPattern::GetAsString() const {
  5185. + if (!spec_.empty())
  5186. + return spec_;
  5187. +
  5188. + if (match_all_urls_) {
  5189. + spec_ = kAllUrlsPattern;
  5190. + return spec_;
  5191. + }
  5192. +
  5193. + bool standard_scheme = IsStandardScheme(scheme_);
  5194. +
  5195. + std::string spec = scheme_ +
  5196. + (standard_scheme ? url::kStandardSchemeSeparator : ":");
  5197. +
  5198. + if (scheme_ != url::kFileScheme && standard_scheme) {
  5199. + if (match_subdomains_) {
  5200. + spec += "*";
  5201. + if (!host_.empty())
  5202. + spec += ".";
  5203. + }
  5204. +
  5205. + if (!host_.empty())
  5206. + spec += host_;
  5207. +
  5208. + if (port_ != "*") {
  5209. + spec += ":";
  5210. + spec += port_;
  5211. + }
  5212. + }
  5213. +
  5214. + if (!path_.empty())
  5215. + spec += path_;
  5216. +
  5217. + spec_ = std::move(spec);
  5218. + return spec_;
  5219. +}
  5220. +
  5221. +bool URLPattern::OverlapsWith(const URLPattern& other) const {
  5222. + if (match_all_urls() || other.match_all_urls())
  5223. + return true;
  5224. + return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
  5225. + other.MatchesAnyScheme(GetExplicitSchemes()))
  5226. + && (MatchesHost(other.host()) || other.MatchesHost(host()))
  5227. + && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
  5228. + && (MatchesPath(StripTrailingWildcard(other.path())) ||
  5229. + other.MatchesPath(StripTrailingWildcard(path())));
  5230. +}
  5231. +
  5232. +bool URLPattern::Contains(const URLPattern& other) const {
  5233. + // Important: it's not enough to just check match_all_urls(); we also need to
  5234. + // make sure that the schemes in this pattern are a superset of those in
  5235. + // |other|.
  5236. + if (match_all_urls() &&
  5237. + (valid_schemes_ & other.valid_schemes_) == other.valid_schemes_) {
  5238. + return true;
  5239. + }
  5240. +
  5241. + return MatchesAllSchemes(other.GetExplicitSchemes()) &&
  5242. + MatchesHost(other.host()) &&
  5243. + (!other.match_subdomains_ || match_subdomains_) &&
  5244. + MatchesPortPattern(other.port()) &&
  5245. + MatchesPath(StripTrailingWildcard(other.path()));
  5246. +}
  5247. +
  5248. +base::Optional<URLPattern> URLPattern::CreateIntersection(
  5249. + const URLPattern& other) const {
  5250. + // Easy case: Schemes don't overlap. Return nullopt.
  5251. + int intersection_schemes = URLPattern::SCHEME_NONE;
  5252. + if (valid_schemes_ == URLPattern::SCHEME_ALL)
  5253. + intersection_schemes = other.valid_schemes_;
  5254. + else if (other.valid_schemes_ == URLPattern::SCHEME_ALL)
  5255. + intersection_schemes = valid_schemes_;
  5256. + else
  5257. + intersection_schemes = valid_schemes_ & other.valid_schemes_;
  5258. +
  5259. + if (intersection_schemes == URLPattern::SCHEME_NONE)
  5260. + return base::nullopt;
  5261. +
  5262. + {
  5263. + // In a few cases, we can (mostly) return a copy of one of the patterns.
  5264. + // This can happen when either:
  5265. + // - The URLPattern's are identical (possibly excluding valid_schemes_)
  5266. + // - One of the patterns has match_all_urls() equal to true.
  5267. + // NOTE(devlin): Theoretically, we could use Contains() instead of
  5268. + // match_all_urls() here. However, Contains() strips the trailing wildcard
  5269. + // from the path, which could yield the incorrect result.
  5270. + const URLPattern* copy_source = nullptr;
  5271. + if (*this == other || other.match_all_urls())
  5272. + copy_source = this;
  5273. + else if (match_all_urls())
  5274. + copy_source = &other;
  5275. +
  5276. + if (copy_source) {
  5277. + // NOTE: equality checks don't take into account valid_schemes_, and
  5278. + // schemes can be different in the case of match_all_urls() as well, so
  5279. + // we can't always just return *copy_source.
  5280. + if (intersection_schemes == copy_source->valid_schemes_)
  5281. + return *copy_source;
  5282. + URLPattern result(intersection_schemes);
  5283. + ParseResult parse_result = result.Parse(copy_source->GetAsString());
  5284. + CHECK_EQ(ParseResult::kSuccess, parse_result);
  5285. + return result;
  5286. + }
  5287. + }
  5288. +
  5289. + // No more easy cases. Go through component by component to find the patterns
  5290. + // that intersect.
  5291. +
  5292. + // Note: Alias the function type (rather than using auto) because
  5293. + // MatchesHost() is overloaded.
  5294. + using match_function_type = bool (URLPattern::*)(base::StringPiece) const;
  5295. +
  5296. + auto get_intersection = [this, &other](base::StringPiece own_str,
  5297. + base::StringPiece other_str,
  5298. + match_function_type match_function,
  5299. + base::StringPiece* out) {
  5300. + if ((this->*match_function)(other_str)) {
  5301. + *out = other_str;
  5302. + return true;
  5303. + }
  5304. + if ((other.*match_function)(own_str)) {
  5305. + *out = own_str;
  5306. + return true;
  5307. + }
  5308. + return false;
  5309. + };
  5310. +
  5311. + base::StringPiece scheme;
  5312. + base::StringPiece host;
  5313. + base::StringPiece port;
  5314. + base::StringPiece path;
  5315. + // If any pieces fail to overlap, then there is no intersection.
  5316. + if (!get_intersection(scheme_, other.scheme_, &URLPattern::MatchesScheme,
  5317. + &scheme) ||
  5318. + !get_intersection(host_, other.host_, &URLPattern::MatchesHost, &host) ||
  5319. + !get_intersection(port_, other.port_, &URLPattern::MatchesPortPattern,
  5320. + &port) ||
  5321. + !get_intersection(path_, other.path_, &URLPattern::MatchesPath, &path)) {
  5322. + return base::nullopt;
  5323. + }
  5324. +
  5325. + // Only match subdomains if both patterns match subdomains.
  5326. + base::StringPiece subdomains;
  5327. + if (match_subdomains_ && other.match_subdomains_) {
  5328. + // The host may be empty (e.g., in the case of *://*/* - in that case, only
  5329. + // append '*' instead of '*.'.
  5330. + subdomains = host.empty() ? "*" : "*.";
  5331. + }
  5332. +
  5333. + base::StringPiece scheme_separator =
  5334. + IsStandardScheme(scheme) ? url::kStandardSchemeSeparator : ":";
  5335. +
  5336. + std::string pattern_str = base::StrCat(
  5337. + {scheme, scheme_separator, subdomains, host, ":", port, path});
  5338. +
  5339. + URLPattern pattern(intersection_schemes);
  5340. + ParseResult result = pattern.Parse(pattern_str);
  5341. + // TODO(devlin): I don't think there's any way this should ever fail, but
  5342. + // use a CHECK() to flush any cases out. If nothing crops up, downgrade this
  5343. + // to a DCHECK in M72.
  5344. + CHECK_EQ(ParseResult::kSuccess, result);
  5345. +
  5346. + return pattern;
  5347. +}
  5348. +
  5349. +bool URLPattern::MatchesAnyScheme(
  5350. + const std::vector<std::string>& schemes) const {
  5351. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5352. + if (MatchesScheme(*i))
  5353. + return true;
  5354. + }
  5355. +
  5356. + return false;
  5357. +}
  5358. +
  5359. +bool URLPattern::MatchesAllSchemes(
  5360. + const std::vector<std::string>& schemes) const {
  5361. + for (auto i = schemes.cbegin(); i != schemes.cend(); ++i) {
  5362. + if (!MatchesScheme(*i))
  5363. + return false;
  5364. + }
  5365. +
  5366. + return true;
  5367. +}
  5368. +
  5369. +bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
  5370. + // Ignore hostname if scheme is file://.
  5371. + if (scheme_ != url::kFileScheme && !MatchesHost(test))
  5372. + return false;
  5373. +
  5374. + if (!MatchesPortPattern(base::NumberToString(test.EffectiveIntPort())))
  5375. + return false;
  5376. +
  5377. + return true;
  5378. +}
  5379. +
  5380. +bool URLPattern::MatchesPortPattern(base::StringPiece port) const {
  5381. + return port_ == "*" || port_ == port;
  5382. +}
  5383. +
  5384. +std::vector<std::string> URLPattern::GetExplicitSchemes() const {
  5385. + std::vector<std::string> result;
  5386. +
  5387. + if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
  5388. + result.push_back(scheme_);
  5389. + return result;
  5390. + }
  5391. +
  5392. + for (size_t i = 0; i < base::size(kValidSchemes); ++i) {
  5393. + if (MatchesScheme(kValidSchemes[i])) {
  5394. + result.push_back(kValidSchemes[i]);
  5395. + }
  5396. + }
  5397. +
  5398. + return result;
  5399. +}
  5400. +
  5401. +std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
  5402. + std::vector<std::string> explicit_schemes = GetExplicitSchemes();
  5403. + std::vector<URLPattern> result;
  5404. +
  5405. + for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
  5406. + i != explicit_schemes.end(); ++i) {
  5407. + URLPattern temp = *this;
  5408. + temp.SetScheme(*i);
  5409. + temp.SetMatchAllURLs(false);
  5410. + result.push_back(temp);
  5411. + }
  5412. +
  5413. + return result;
  5414. +}
  5415. +
  5416. +// static
  5417. +const char* URLPattern::GetParseResultString(
  5418. + URLPattern::ParseResult parse_result) {
  5419. + return kParseResultMessages[static_cast<int>(parse_result)];
  5420. +}
  5421. diff --git a/components/user_scripts/common/url_pattern.h b/components/user_scripts/common/url_pattern.h
  5422. new file mode 100755
  5423. --- /dev/null
  5424. +++ b/components/user_scripts/common/url_pattern.h
  5425. @@ -0,0 +1,301 @@
  5426. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5427. +// Use of this source code is governed by a BSD-style license that can be
  5428. +// found in the LICENSE file.
  5429. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_H_
  5430. +#define USERSCRIPTS_COMMON_URL_PATTERN_H_
  5431. +
  5432. +#include <functional>
  5433. +#include <iosfwd>
  5434. +#include <string>
  5435. +#include <vector>
  5436. +
  5437. +#include "base/strings/string_piece.h"
  5438. +#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  5439. +
  5440. +class GURL;
  5441. +
  5442. +// A pattern that can be used to match URLs. A URLPattern is a very restricted
  5443. +// subset of URL syntax:
  5444. +//
  5445. +// <url-pattern> := <scheme>://<host><port><path> | '<all_urls>'
  5446. +// <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' |
  5447. +// 'chrome-extension' | 'filesystem'
  5448. +// <host> := '*' | <IPv4 address> | [<IPv6 address>] |
  5449. +// '*.' <anychar except '/' and '*'>+
  5450. +// <port> := [':' ('*' | <port number between 0 and 65535>)]
  5451. +// <path> := '/' <any chars>
  5452. +//
  5453. +// * Host is not used when the scheme is 'file'.
  5454. +// * The path can have embedded '*' characters which act as glob wildcards.
  5455. +// * '<all_urls>' is a special pattern that matches any valid URL that contains
  5456. +// a valid scheme (as specified by valid_schemes_).
  5457. +// * The '*' scheme pattern excludes file URLs.
  5458. +//
  5459. +// Examples of valid patterns:
  5460. +// - http://*/*
  5461. +// - http://*/foo*
  5462. +// - https://*.google.com/foo*bar
  5463. +// - file://monkey*
  5464. +// - http://127.0.0.1/*
  5465. +// - http://[2607:f8b0:4005:805::200e]/*
  5466. +//
  5467. +// Examples of invalid patterns:
  5468. +// - http://* -- path not specified
  5469. +// - http://*foo/bar -- * not allowed as substring of host component
  5470. +// - http://foo.*.bar/baz -- * must be first component
  5471. +// - http:/bar -- scheme separator not found
  5472. +// - foo://* -- invalid scheme
  5473. +// - chrome:// -- we don't support chrome internal URLs
  5474. +class URLPattern {
  5475. + public:
  5476. + // A collection of scheme bitmasks for use with valid_schemes.
  5477. + enum SchemeMasks {
  5478. + SCHEME_NONE = 0,
  5479. + SCHEME_HTTP = 1 << 0,
  5480. + SCHEME_HTTPS = 1 << 1,
  5481. + SCHEME_FILE = 1 << 2,
  5482. + SCHEME_FTP = 1 << 3,
  5483. + SCHEME_CHROMEUI = 1 << 4,
  5484. + SCHEME_EXTENSION = 1 << 5,
  5485. + SCHEME_FILESYSTEM = 1 << 6,
  5486. + SCHEME_WS = 1 << 7,
  5487. + SCHEME_WSS = 1 << 8,
  5488. + SCHEME_DATA = 1 << 9,
  5489. +
  5490. + // IMPORTANT!
  5491. + // SCHEME_ALL will match every scheme, including chrome://, chrome-
  5492. + // extension://, about:, etc. Because this has lots of security
  5493. + // implications, third-party extensions should usually not be able to get
  5494. + // access to URL patterns initialized this way. If there is a reason
  5495. + // for violating this general rule, document why this it safe.
  5496. + SCHEME_ALL = -1,
  5497. + };
  5498. +
  5499. + // Error codes returned from Parse().
  5500. + enum class ParseResult {
  5501. + kSuccess = 0,
  5502. + kMissingSchemeSeparator,
  5503. + kInvalidScheme,
  5504. + kWrongSchemeSeparator,
  5505. + kEmptyHost,
  5506. + kInvalidHostWildcard,
  5507. + kEmptyPath,
  5508. + kInvalidPort,
  5509. + kInvalidHost,
  5510. + kNumParseResults,
  5511. + };
  5512. +
  5513. + // The <all_urls> string pattern.
  5514. + static const char kAllUrlsPattern[];
  5515. +
  5516. + // Returns true if the given |scheme| is considered valid for extensions.
  5517. + static bool IsValidSchemeForExtensions(base::StringPiece scheme);
  5518. +
  5519. + // Returns the mask for all schemes considered valid for extensions.
  5520. + static int GetValidSchemeMaskForExtensions();
  5521. +
  5522. + explicit URLPattern(int valid_schemes);
  5523. +
  5524. + // Convenience to construct a URLPattern from a string. If the string is not
  5525. + // known ahead of time, use Parse() instead, which returns success or failure.
  5526. + URLPattern(int valid_schemes, base::StringPiece pattern);
  5527. +
  5528. + URLPattern();
  5529. + URLPattern(const URLPattern& other);
  5530. + URLPattern(URLPattern&& other);
  5531. + ~URLPattern();
  5532. +
  5533. + URLPattern& operator=(const URLPattern& other);
  5534. + URLPattern& operator=(URLPattern&& other);
  5535. +
  5536. + bool operator<(const URLPattern& other) const;
  5537. + bool operator>(const URLPattern& other) const;
  5538. + bool operator==(const URLPattern& other) const;
  5539. +
  5540. + // Initializes this instance by parsing the provided string. Returns
  5541. + // URLPattern::ParseResult::kSuccess on success, or an error code otherwise.
  5542. + // On failure, this instance will have some intermediate values and is in an
  5543. + // invalid state.
  5544. + ParseResult Parse(base::StringPiece pattern_str);
  5545. +
  5546. + // Gets the bitmask of valid schemes.
  5547. + int valid_schemes() const { return valid_schemes_; }
  5548. + void SetValidSchemes(int valid_schemes);
  5549. +
  5550. + // Gets the host the pattern matches. This can be an empty string if the
  5551. + // pattern matches all hosts (the input was <scheme>://*/<whatever>).
  5552. + const std::string& host() const { return host_; }
  5553. + void SetHost(base::StringPiece host);
  5554. +
  5555. + // Gets whether to match subdomains of host().
  5556. + bool match_subdomains() const { return match_subdomains_; }
  5557. + void SetMatchSubdomains(bool val);
  5558. +
  5559. + // Gets the path the pattern matches with the leading slash. This can have
  5560. + // embedded asterisks which are interpreted using glob rules.
  5561. + const std::string& path() const { return path_; }
  5562. + void SetPath(base::StringPiece path);
  5563. +
  5564. + // Returns true if this pattern matches all (valid) urls.
  5565. + bool match_all_urls() const { return match_all_urls_; }
  5566. + void SetMatchAllURLs(bool val);
  5567. +
  5568. + // Sets the scheme for pattern matches. This can be a single '*' if the
  5569. + // pattern matches all valid schemes (as defined by the valid_schemes_
  5570. + // property). Returns false on failure (if the scheme is not valid).
  5571. + bool SetScheme(base::StringPiece scheme);
  5572. + // Note: You should use MatchesScheme() instead of this getter unless you
  5573. + // absolutely need the exact scheme. This is exposed for testing.
  5574. + const std::string& scheme() const { return scheme_; }
  5575. +
  5576. + // Returns true if the specified scheme can be used in this URL pattern, and
  5577. + // false otherwise. Uses valid_schemes_ to determine validity.
  5578. + bool IsValidScheme(base::StringPiece scheme) const;
  5579. +
  5580. + // Returns true if this instance matches the specified URL. Always returns
  5581. + // false for invalid URLs.
  5582. + bool MatchesURL(const GURL& test) const;
  5583. +
  5584. + // Returns true if this instance matches the specified security origin.
  5585. + bool MatchesSecurityOrigin(const GURL& test) const;
  5586. +
  5587. + // Returns true if |test| matches our scheme.
  5588. + // Note that if test is "filesystem", this may fail whereas MatchesURL
  5589. + // may succeed. MatchesURL is smart enough to look at the inner_url instead
  5590. + // of the outer "filesystem:" part.
  5591. + bool MatchesScheme(base::StringPiece test) const;
  5592. +
  5593. + // Returns true if |test| matches our host.
  5594. + bool MatchesHost(base::StringPiece test) const;
  5595. + bool MatchesHost(const GURL& test) const;
  5596. +
  5597. + // Returns true if |test| matches our path.
  5598. + bool MatchesPath(base::StringPiece test) const;
  5599. +
  5600. + // Returns true if the pattern matches all patterns in an (e)TLD. This
  5601. + // includes patterns like *://*.com/*, *://*.co.uk/*, etc. A pattern that
  5602. + // matches all domains (e.g., *://*/*) will return true.
  5603. + // |private_filter| specifies whether private registries (like appspot.com)
  5604. + // should be considered; if included, patterns like *://*.appspot.com/* will
  5605. + // return true. By default, we exclude private registries (so *.appspot.com
  5606. + // returns false).
  5607. + // Note: This is an expensive method, and should be used sparingly!
  5608. + // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is
  5609. + // cached.
  5610. + bool MatchesEffectiveTld(
  5611. + net::registry_controlled_domains::PrivateRegistryFilter private_filter =
  5612. + net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES,
  5613. + net::registry_controlled_domains::UnknownRegistryFilter unknown_filter =
  5614. + net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES) const;
  5615. +
  5616. + // Returns true if the pattern only matches a single origin. The pattern may
  5617. + // include a path.
  5618. + bool MatchesSingleOrigin() const;
  5619. +
  5620. + // Sets the port. Returns false if the port is invalid.
  5621. + bool SetPort(base::StringPiece port);
  5622. + const std::string& port() const { return port_; }
  5623. +
  5624. + // Returns a string representing this instance.
  5625. + const std::string& GetAsString() const;
  5626. +
  5627. + // Determines whether there is a URL that would match this instance and
  5628. + // another instance. This method is symmetrical: Calling
  5629. + // other.OverlapsWith(this) would result in the same answer.
  5630. + bool OverlapsWith(const URLPattern& other) const;
  5631. +
  5632. + // Returns true if this pattern matches all possible URLs that |other| can
  5633. + // match. For example, http://*.google.com encompasses http://www.google.com.
  5634. + bool Contains(const URLPattern& other) const;
  5635. +
  5636. + // Creates a new URLPattern that represents the intersection of this
  5637. + // URLPattern with the |other|, or base::nullopt if no intersection exists.
  5638. + // For instance, given the patterns http://*.google.com/* and
  5639. + // *://maps.google.com/*, the intersection is http://maps.google.com/*.
  5640. + // NOTES:
  5641. + // - Though scheme intersections are supported, the serialization of
  5642. + // URLPatternSet does not record them. Be sure that this is safe for your
  5643. + // use cases.
  5644. + // - Path intersection is done on a best-effort basis. If one path clearly
  5645. + // contains another, it will be handled correctly, but this method does not
  5646. + // deal with cases like /*a* and /*b* (where technically the intersection
  5647. + // is /*a*b*|/*b*a*); the intersection returned for that case will be empty.
  5648. + base::Optional<URLPattern> CreateIntersection(const URLPattern& other) const;
  5649. +
  5650. + // Converts this URLPattern into an equivalent set of URLPatterns that don't
  5651. + // use a wildcard in the scheme component. If this URLPattern doesn't use a
  5652. + // wildcard scheme, then the returned set will contain one element that is
  5653. + // equivalent to this instance.
  5654. + std::vector<URLPattern> ConvertToExplicitSchemes() const;
  5655. +
  5656. + static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) {
  5657. + if (a.match_all_urls_ && b.match_all_urls_)
  5658. + return false;
  5659. + return a.host_.compare(b.host_) < 0;
  5660. + }
  5661. +
  5662. + // Used for origin comparisons in a std::set.
  5663. + class EffectiveHostCompareFunctor {
  5664. + public:
  5665. + bool operator()(const URLPattern& a, const URLPattern& b) const {
  5666. + return EffectiveHostCompare(a, b);
  5667. + }
  5668. + };
  5669. +
  5670. + // Get an error string for a ParseResult.
  5671. + static const char* GetParseResultString(URLPattern::ParseResult parse_result);
  5672. +
  5673. + private:
  5674. + // Returns true if any of the |schemes| items matches our scheme.
  5675. + bool MatchesAnyScheme(const std::vector<std::string>& schemes) const;
  5676. +
  5677. + // Returns true if all of the |schemes| items matches our scheme.
  5678. + bool MatchesAllSchemes(const std::vector<std::string>& schemes) const;
  5679. +
  5680. + bool MatchesSecurityOriginHelper(const GURL& test) const;
  5681. +
  5682. + // Returns true if our port matches the |port| pattern (it may be "*").
  5683. + bool MatchesPortPattern(base::StringPiece port) const;
  5684. +
  5685. + // If the URLPattern contains a wildcard scheme, returns a list of
  5686. + // equivalent literal schemes, otherwise returns the current scheme.
  5687. + std::vector<std::string> GetExplicitSchemes() const;
  5688. +
  5689. + // A bitmask containing the schemes which are considered valid for this
  5690. + // pattern. Parse() uses this to decide whether a pattern contains a valid
  5691. + // scheme.
  5692. + int valid_schemes_;
  5693. +
  5694. + // True if this is a special-case "<all_urls>" pattern.
  5695. + bool match_all_urls_;
  5696. +
  5697. + // The scheme for the pattern.
  5698. + std::string scheme_;
  5699. +
  5700. + // The host without any leading "*" components.
  5701. + std::string host_;
  5702. +
  5703. + // Whether we should match subdomains of the host. This is true if the first
  5704. + // component of the pattern's host was "*".
  5705. + bool match_subdomains_;
  5706. +
  5707. + // The port.
  5708. + std::string port_;
  5709. +
  5710. + // The path to match. This is everything after the host of the URL, or
  5711. + // everything after the scheme in the case of file:// URLs.
  5712. + std::string path_;
  5713. +
  5714. + // The path with "?" and "\" characters escaped for use with the
  5715. + // MatchPattern() function.
  5716. + std::string path_escaped_;
  5717. +
  5718. + // A string representing this URLPattern.
  5719. + mutable std::string spec_;
  5720. +};
  5721. +
  5722. +std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern);
  5723. +
  5724. +typedef std::vector<URLPattern> URLPatternList;
  5725. +
  5726. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_H_
  5727. diff --git a/components/user_scripts/common/url_pattern_set.cc b/components/user_scripts/common/url_pattern_set.cc
  5728. new file mode 100755
  5729. --- /dev/null
  5730. +++ b/components/user_scripts/common/url_pattern_set.cc
  5731. @@ -0,0 +1,330 @@
  5732. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  5733. +// Use of this source code is governed by a BSD-style license that can be
  5734. +// found in the LICENSE file.
  5735. +
  5736. +#include "url_pattern_set.h"
  5737. +
  5738. +#include <iterator>
  5739. +#include <ostream>
  5740. +
  5741. +#include "base/logging.h"
  5742. +#include "base/stl_util.h"
  5743. +#include "base/values.h"
  5744. +#include "error_utils.h"
  5745. +#include "url_pattern.h"
  5746. +#include "url/gurl.h"
  5747. +#include "url/origin.h"
  5748. +#include "url/url_constants.h"
  5749. +#include "user_scripts_features.h"
  5750. +
  5751. +namespace user_scripts {
  5752. +
  5753. +namespace {
  5754. +
  5755. +const char kInvalidURLPatternError[] = "Invalid url pattern '*'";
  5756. +
  5757. +} // namespace
  5758. +
  5759. +// static
  5760. +URLPatternSet URLPatternSet::CreateDifference(const URLPatternSet& set1,
  5761. + const URLPatternSet& set2) {
  5762. + return URLPatternSet(base::STLSetDifference<std::set<URLPattern>>(
  5763. + set1.patterns_, set2.patterns_));
  5764. +}
  5765. +
  5766. +// static
  5767. +URLPatternSet URLPatternSet::CreateIntersection(
  5768. + const URLPatternSet& set1,
  5769. + const URLPatternSet& set2,
  5770. + IntersectionBehavior intersection_behavior) {
  5771. + // Note: leverage return value optimization; always return the same object.
  5772. + URLPatternSet result;
  5773. +
  5774. + if (intersection_behavior == IntersectionBehavior::kStringComparison) {
  5775. + // String comparison just relies on STL set behavior, which looks at the
  5776. + // string representation.
  5777. + result = URLPatternSet(base::STLSetIntersection<std::set<URLPattern>>(
  5778. + set1.patterns_, set2.patterns_));
  5779. + return result;
  5780. + }
  5781. +
  5782. + // Look for a semantic intersection.
  5783. +
  5784. + // Step 1: Iterate over each set. Find any patterns that are completely
  5785. + // contained by the other (thus being necessarily present in any intersection)
  5786. + // and add them, collecting the others in a set of unique items.
  5787. + // Note: Use a collection of pointers for the uniques to avoid excessive
  5788. + // copies. Since these are owned by the URLPatternSet passed in, which is
  5789. + // const, this should be safe.
  5790. + std::vector<const URLPattern*> unique_set1;
  5791. + for (const URLPattern& pattern : set1) {
  5792. + if (set2.ContainsPattern(pattern))
  5793. + result.patterns_.insert(pattern);
  5794. + else
  5795. + unique_set1.push_back(&pattern);
  5796. + }
  5797. + std::vector<const URLPattern*> unique_set2;
  5798. + for (const URLPattern& pattern : set2) {
  5799. + if (set1.ContainsPattern(pattern))
  5800. + result.patterns_.insert(pattern);
  5801. + else
  5802. + unique_set2.push_back(&pattern);
  5803. + }
  5804. +
  5805. + // If we're just looking for patterns contained by both, we're done.
  5806. + if (intersection_behavior == IntersectionBehavior::kPatternsContainedByBoth)
  5807. + return result;
  5808. +
  5809. + DCHECK_EQ(IntersectionBehavior::kDetailed, intersection_behavior);
  5810. +
  5811. + // Step 2: Iterate over all the unique patterns and find the intersections
  5812. + // they have with the other patterns.
  5813. + for (const auto* pattern : unique_set1) {
  5814. + for (const auto* pattern2 : unique_set2) {
  5815. + base::Optional<URLPattern> intersection =
  5816. + pattern->CreateIntersection(*pattern2);
  5817. + if (intersection)
  5818. + result.patterns_.insert(std::move(*intersection));
  5819. + }
  5820. + }
  5821. +
  5822. + return result;
  5823. +}
  5824. +
  5825. +// static
  5826. +URLPatternSet URLPatternSet::CreateUnion(const URLPatternSet& set1,
  5827. + const URLPatternSet& set2) {
  5828. + return URLPatternSet(
  5829. + base::STLSetUnion<std::set<URLPattern>>(set1.patterns_, set2.patterns_));
  5830. +}
  5831. +
  5832. +// static
  5833. +URLPatternSet URLPatternSet::CreateUnion(
  5834. + const std::vector<URLPatternSet>& sets) {
  5835. + URLPatternSet result;
  5836. + if (sets.empty())
  5837. + return result;
  5838. +
  5839. + // N-way union algorithm is basic O(nlog(n)) merge algorithm.
  5840. + //
  5841. + // Do the first merge step into a working set so that we don't mutate any of
  5842. + // the input.
  5843. + // TODO(devlin): Looks like this creates a bunch of copies; we can probably
  5844. + // clean that up.
  5845. + std::vector<URLPatternSet> working;
  5846. + for (size_t i = 0; i < sets.size(); i += 2) {
  5847. + if (i + 1 < sets.size())
  5848. + working.push_back(CreateUnion(sets[i], sets[i + 1]));
  5849. + else
  5850. + working.push_back(sets[i].Clone());
  5851. + }
  5852. +
  5853. + for (size_t skip = 1; skip < working.size(); skip *= 2) {
  5854. + for (size_t i = 0; i < (working.size() - skip); i += skip) {
  5855. + URLPatternSet u = CreateUnion(working[i], working[i + skip]);
  5856. + working[i].patterns_.swap(u.patterns_);
  5857. + }
  5858. + }
  5859. +
  5860. + result.patterns_.swap(working[0].patterns_);
  5861. + return result;
  5862. +}
  5863. +
  5864. +URLPatternSet::URLPatternSet() = default;
  5865. +
  5866. +URLPatternSet::URLPatternSet(URLPatternSet&& rhs) = default;
  5867. +
  5868. +URLPatternSet::URLPatternSet(const std::set<URLPattern>& patterns)
  5869. + : patterns_(patterns) {}
  5870. +
  5871. +URLPatternSet::~URLPatternSet() = default;
  5872. +
  5873. +URLPatternSet& URLPatternSet::operator=(URLPatternSet&& rhs) = default;
  5874. +
  5875. +bool URLPatternSet::operator==(const URLPatternSet& other) const {
  5876. + return patterns_ == other.patterns_;
  5877. +}
  5878. +
  5879. +std::ostream& operator<<(std::ostream& out,
  5880. + const URLPatternSet& url_pattern_set) {
  5881. + out << "{ ";
  5882. +
  5883. + auto iter = url_pattern_set.patterns().cbegin();
  5884. + if (!url_pattern_set.patterns().empty()) {
  5885. + out << *iter;
  5886. + ++iter;
  5887. + }
  5888. +
  5889. + for (;iter != url_pattern_set.patterns().end(); ++iter)
  5890. + out << ", " << *iter;
  5891. +
  5892. + if (!url_pattern_set.patterns().empty())
  5893. + out << " ";
  5894. +
  5895. + out << "}";
  5896. + return out;
  5897. +}
  5898. +
  5899. +URLPatternSet URLPatternSet::Clone() const {
  5900. + return URLPatternSet(patterns_);
  5901. +}
  5902. +
  5903. +bool URLPatternSet::is_empty() const {
  5904. + return patterns_.empty();
  5905. +}
  5906. +
  5907. +size_t URLPatternSet::size() const {
  5908. + return patterns_.size();
  5909. +}
  5910. +
  5911. +bool URLPatternSet::AddPattern(const URLPattern& pattern) {
  5912. + return patterns_.insert(pattern).second;
  5913. +}
  5914. +
  5915. +void URLPatternSet::AddPatterns(const URLPatternSet& set) {
  5916. + patterns_.insert(set.patterns().begin(),
  5917. + set.patterns().end());
  5918. +}
  5919. +
  5920. +void URLPatternSet::ClearPatterns() {
  5921. + patterns_.clear();
  5922. +}
  5923. +
  5924. +bool URLPatternSet::AddOrigin(int valid_schemes, const GURL& origin) {
  5925. + if (origin.is_empty())
  5926. + return false;
  5927. + const url::Origin real_origin = url::Origin::Create(origin);
  5928. + DCHECK(real_origin.IsSameOriginWith(url::Origin::Create(origin.GetOrigin())));
  5929. + URLPattern origin_pattern(valid_schemes);
  5930. + // Origin adding could fail if |origin| does not match |valid_schemes|.
  5931. + if (origin_pattern.Parse(origin.spec()) !=
  5932. + URLPattern::ParseResult::kSuccess) {
  5933. + return false;
  5934. + }
  5935. + origin_pattern.SetPath("/*");
  5936. + return AddPattern(origin_pattern);
  5937. +}
  5938. +
  5939. +bool URLPatternSet::Contains(const URLPatternSet& other) const {
  5940. + for (auto it = other.begin(); it != other.end(); ++it) {
  5941. + if (!ContainsPattern(*it))
  5942. + return false;
  5943. + }
  5944. +
  5945. + return true;
  5946. +}
  5947. +
  5948. +bool URLPatternSet::ContainsPattern(const URLPattern& pattern) const {
  5949. + for (auto it = begin(); it != end(); ++it) {
  5950. + if (it->Contains(pattern))
  5951. + return true;
  5952. + }
  5953. + return false;
  5954. +}
  5955. +
  5956. +bool URLPatternSet::MatchesURL(const GURL& url) const {
  5957. + for (auto pattern = patterns_.cbegin(); pattern != patterns_.cend();
  5958. + ++pattern) {
  5959. + if (pattern->MatchesURL(url)) {
  5960. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5961. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL true " << url.spec();
  5962. +
  5963. + return true;
  5964. + }
  5965. + }
  5966. +
  5967. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  5968. + LOG(INFO) << "UserScripts: URLPatternSet::MatchesURL false " << url.spec();
  5969. +
  5970. + return false;
  5971. +}
  5972. +
  5973. +bool URLPatternSet::MatchesAllURLs() const {
  5974. + for (auto host = begin(); host != end(); ++host) {
  5975. + if (host->match_all_urls() ||
  5976. + (host->match_subdomains() && host->host().empty()))
  5977. + return true;
  5978. + }
  5979. + return false;
  5980. +}
  5981. +
  5982. +bool URLPatternSet::MatchesSecurityOrigin(const GURL& origin) const {
  5983. + for (auto pattern = patterns_.begin(); pattern != patterns_.end();
  5984. + ++pattern) {
  5985. + if (pattern->MatchesSecurityOrigin(origin))
  5986. + return true;
  5987. + }
  5988. +
  5989. + return false;
  5990. +}
  5991. +
  5992. +bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const {
  5993. + // Two extension extents overlap if there is any one URL that would match at
  5994. + // least one pattern in each of the extents.
  5995. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  5996. + for (auto j = other.patterns().cbegin(); j != other.patterns().cend();
  5997. + ++j) {
  5998. + if (i->OverlapsWith(*j))
  5999. + return true;
  6000. + }
  6001. + }
  6002. +
  6003. + return false;
  6004. +}
  6005. +
  6006. +std::unique_ptr<base::ListValue> URLPatternSet::ToValue() const {
  6007. + std::unique_ptr<base::ListValue> value(new base::ListValue);
  6008. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i)
  6009. + value->AppendIfNotPresent(std::make_unique<base::Value>(i->GetAsString()));
  6010. + return value;
  6011. +}
  6012. +
  6013. +bool URLPatternSet::Populate(const std::vector<std::string>& patterns,
  6014. + int valid_schemes,
  6015. + bool allow_file_access,
  6016. + std::string* error) {
  6017. + ClearPatterns();
  6018. + for (size_t i = 0; i < patterns.size(); ++i) {
  6019. + URLPattern pattern(valid_schemes);
  6020. + if (pattern.Parse(patterns[i]) != URLPattern::ParseResult::kSuccess) {
  6021. + if (error) {
  6022. + *error = ErrorUtils::FormatErrorMessage(kInvalidURLPatternError,
  6023. + patterns[i]);
  6024. + } else {
  6025. + LOG(ERROR) << "Invalid url pattern: " << patterns[i];
  6026. + }
  6027. + return false;
  6028. + }
  6029. + if (!allow_file_access && pattern.MatchesScheme(url::kFileScheme)) {
  6030. + pattern.SetValidSchemes(
  6031. + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
  6032. + }
  6033. + AddPattern(pattern);
  6034. + }
  6035. + return true;
  6036. +}
  6037. +
  6038. +std::unique_ptr<std::vector<std::string>> URLPatternSet::ToStringVector()
  6039. + const {
  6040. + std::unique_ptr<std::vector<std::string>> value(new std::vector<std::string>);
  6041. + for (auto i = patterns_.cbegin(); i != patterns_.cend(); ++i) {
  6042. + value->push_back(i->GetAsString());
  6043. + }
  6044. + return value;
  6045. +}
  6046. +
  6047. +bool URLPatternSet::Populate(const base::ListValue& value,
  6048. + int valid_schemes,
  6049. + bool allow_file_access,
  6050. + std::string* error) {
  6051. + std::vector<std::string> patterns;
  6052. + for (size_t i = 0; i < value.GetSize(); ++i) {
  6053. + std::string item;
  6054. + if (!value.GetString(i, &item))
  6055. + return false;
  6056. + patterns.push_back(item);
  6057. + }
  6058. + return Populate(patterns, valid_schemes, allow_file_access, error);
  6059. +}
  6060. +
  6061. +} // namespace extensions
  6062. diff --git a/components/user_scripts/common/url_pattern_set.h b/components/user_scripts/common/url_pattern_set.h
  6063. new file mode 100755
  6064. --- /dev/null
  6065. +++ b/components/user_scripts/common/url_pattern_set.h
  6066. @@ -0,0 +1,161 @@
  6067. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  6068. +// Use of this source code is governed by a BSD-style license that can be
  6069. +// found in the LICENSE file.
  6070. +
  6071. +#ifndef USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6072. +#define USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6073. +
  6074. +#include <stddef.h>
  6075. +
  6076. +#include <iosfwd>
  6077. +#include <memory>
  6078. +#include <set>
  6079. +
  6080. +#include "base/macros.h"
  6081. +#include "url_pattern.h"
  6082. +
  6083. +class GURL;
  6084. +
  6085. +namespace base {
  6086. +class ListValue;
  6087. +class Value;
  6088. +}
  6089. +
  6090. +namespace user_scripts {
  6091. +
  6092. +// Represents the set of URLs an extension uses for web content.
  6093. +class URLPatternSet {
  6094. + public:
  6095. + typedef std::set<URLPattern>::const_iterator const_iterator;
  6096. + typedef std::set<URLPattern>::iterator iterator;
  6097. +
  6098. + // Returns |set1| - |set2|.
  6099. + static URLPatternSet CreateDifference(const URLPatternSet& set1,
  6100. + const URLPatternSet& set2);
  6101. +
  6102. + enum class IntersectionBehavior {
  6103. + // For the following descriptions, consider the two URLPatternSets:
  6104. + // Set 1: {"https://example.com/*", "https://*.google.com/*", "http://*/*"}
  6105. + // Set 2: {"https://example.com/*", "https://google.com/maps",
  6106. + // "*://chromium.org/*"}
  6107. +
  6108. + // Only includes patterns that are exactly in both sets. The intersection of
  6109. + // the two sets above is {"https://example.com/*"}, since that is the only
  6110. + // pattern that appears exactly in each.
  6111. + kStringComparison,
  6112. +
  6113. + // Includes patterns that are effectively contained by both sets. The
  6114. + // intersection of the two sets above is
  6115. + // {
  6116. + // "https://example.com/*" (contained exactly by each set)
  6117. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6118. + // subset of https://*.google.com/* in set 1)
  6119. + // }
  6120. + kPatternsContainedByBoth,
  6121. +
  6122. + // Includes patterns that are contained by both sets and creates new
  6123. + // patterns to represent the intersection of any others. The intersection of
  6124. + // the two sets above is
  6125. + // {
  6126. + // "https://example.com/*" (contained exactly by each set)
  6127. + // "https://google.com/maps" (contained exactly by set 2 and a strict
  6128. + // subset of https://*.google.com/* in set 1)
  6129. + // "http://chromium.org/*" (the overlap between "http://*/*" in set 1 and
  6130. + // *://chromium.org/*" in set 2).
  6131. + // }
  6132. + // Note that this is the most computationally expensive - potentially
  6133. + // O(n^2) - since it can require comparing each pattern in one set to every
  6134. + // pattern in the other set.
  6135. + kDetailed,
  6136. + };
  6137. +
  6138. + // Returns the intersection of |set1| and |set2| according to
  6139. + // |intersection_behavior|.
  6140. + static URLPatternSet CreateIntersection(
  6141. + const URLPatternSet& set1,
  6142. + const URLPatternSet& set2,
  6143. + IntersectionBehavior intersection_behavior);
  6144. +
  6145. + // Returns the union of |set1| and |set2|.
  6146. + static URLPatternSet CreateUnion(const URLPatternSet& set1,
  6147. + const URLPatternSet& set2);
  6148. +
  6149. + // Returns the union of all sets in |sets|.
  6150. + static URLPatternSet CreateUnion(const std::vector<URLPatternSet>& sets);
  6151. +
  6152. + URLPatternSet();
  6153. + URLPatternSet(URLPatternSet&& rhs);
  6154. + explicit URLPatternSet(const std::set<URLPattern>& patterns);
  6155. + ~URLPatternSet();
  6156. +
  6157. + URLPatternSet& operator=(URLPatternSet&& rhs);
  6158. + bool operator==(const URLPatternSet& rhs) const;
  6159. +
  6160. + bool is_empty() const;
  6161. + size_t size() const;
  6162. + const std::set<URLPattern>& patterns() const { return patterns_; }
  6163. + const_iterator begin() const { return patterns_.begin(); }
  6164. + const_iterator end() const { return patterns_.end(); }
  6165. + iterator erase(iterator iter) { return patterns_.erase(iter); }
  6166. +
  6167. + // Returns a copy of this URLPatternSet; not instrumented as a copy
  6168. + // constructor to avoid accidental/unnecessary copies.
  6169. + URLPatternSet Clone() const;
  6170. +
  6171. + // Adds a pattern to the set. Returns true if a new pattern was inserted,
  6172. + // false if the pattern was already in the set.
  6173. + bool AddPattern(const URLPattern& pattern);
  6174. +
  6175. + // Adds all patterns from |set| into this.
  6176. + void AddPatterns(const URLPatternSet& set);
  6177. +
  6178. + void ClearPatterns();
  6179. +
  6180. + // Adds a pattern based on |origin| to the set.
  6181. + bool AddOrigin(int valid_schemes, const GURL& origin);
  6182. +
  6183. + // Returns true if every URL that matches |set| is matched by this. In other
  6184. + // words, if every pattern in |set| is encompassed by a pattern in this.
  6185. + bool Contains(const URLPatternSet& set) const;
  6186. +
  6187. + // Returns true if any pattern in this set encompasses |pattern|.
  6188. + bool ContainsPattern(const URLPattern& pattern) const;
  6189. +
  6190. + // Test if the extent contains a URL.
  6191. + bool MatchesURL(const GURL& url) const;
  6192. +
  6193. + // Test if the extent matches all URLs (for example, <all_urls>).
  6194. + bool MatchesAllURLs() const;
  6195. +
  6196. + bool MatchesSecurityOrigin(const GURL& origin) const;
  6197. +
  6198. + // Returns true if there is a single URL that would be in two extents.
  6199. + bool OverlapsWith(const URLPatternSet& other) const;
  6200. +
  6201. + // Converts to and from Value for serialization to preferences.
  6202. + std::unique_ptr<base::ListValue> ToValue() const;
  6203. + bool Populate(const base::ListValue& value,
  6204. + int valid_schemes,
  6205. + bool allow_file_access,
  6206. + std::string* error);
  6207. +
  6208. + // Converts to and from a vector of strings.
  6209. + std::unique_ptr<std::vector<std::string>> ToStringVector() const;
  6210. + bool Populate(const std::vector<std::string>& patterns,
  6211. + int valid_schemes,
  6212. + bool allow_file_access,
  6213. + std::string* error);
  6214. +
  6215. + private:
  6216. + // The list of URL patterns that comprise the extent.
  6217. + std::set<URLPattern> patterns_;
  6218. +
  6219. + DISALLOW_COPY_AND_ASSIGN(URLPatternSet);
  6220. +};
  6221. +
  6222. +std::ostream& operator<<(std::ostream& out,
  6223. + const URLPatternSet& url_pattern_set);
  6224. +
  6225. +} // namespace extensions
  6226. +
  6227. +#endif // USERSCRIPTS_COMMON_URL_PATTERN_SET_H_
  6228. diff --git a/components/user_scripts/common/user_script.cc b/components/user_scripts/common/user_script.cc
  6229. new file mode 100755
  6230. --- /dev/null
  6231. +++ b/components/user_scripts/common/user_script.cc
  6232. @@ -0,0 +1,317 @@
  6233. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6234. +// Use of this source code is governed by a BSD-style license that can be
  6235. +// found in the LICENSE file.
  6236. +
  6237. +#include "user_script.h"
  6238. +
  6239. +#include <stddef.h>
  6240. +#include <stdint.h>
  6241. +
  6242. +#include <memory>
  6243. +#include <utility>
  6244. +
  6245. +#include "base/atomic_sequence_num.h"
  6246. +#include "base/command_line.h"
  6247. +#include "base/pickle.h"
  6248. +#include "base/strings/pattern.h"
  6249. +#include "base/strings/string_util.h"
  6250. +#include "user_scripts_features.h"
  6251. +
  6252. +namespace {
  6253. +
  6254. +// This cannot be a plain int or int64_t because we need to generate unique IDs
  6255. +// from multiple threads.
  6256. +base::AtomicSequenceNumber g_user_script_id_generator;
  6257. +
  6258. +bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  6259. + const GURL& url) {
  6260. + for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  6261. + if (base::MatchPattern(url.spec(), *glob))
  6262. + return true;
  6263. + }
  6264. +
  6265. + return false;
  6266. +}
  6267. +
  6268. +} // namespace
  6269. +
  6270. +namespace user_scripts {
  6271. +
  6272. +// The bitmask for valid user script injectable schemes used by URLPattern.
  6273. +enum {
  6274. + kValidUserScriptSchemes = //URLPattern::SCHEME_CHROMEUI |
  6275. + URLPattern::SCHEME_HTTP |
  6276. + URLPattern::SCHEME_HTTPS
  6277. + //| URLPattern::SCHEME_FILE |
  6278. + //URLPattern::SCHEME_FTP
  6279. +};
  6280. +
  6281. +// static
  6282. +const char UserScript::kFileExtension[] = ".user.js";
  6283. +
  6284. +// static
  6285. +int UserScript::GenerateUserScriptID() {
  6286. + return g_user_script_id_generator.GetNext();
  6287. +}
  6288. +
  6289. +bool UserScript::IsURLUserScript(const GURL& url,
  6290. + const std::string& mime_type) {
  6291. + return base::EndsWith(url.ExtractFileName(), kFileExtension,
  6292. + base::CompareCase::INSENSITIVE_ASCII) &&
  6293. + mime_type != "text/html";
  6294. +}
  6295. +
  6296. +// static
  6297. +int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
  6298. + if (canExecuteScriptEverywhere)
  6299. + return URLPattern::SCHEME_ALL;
  6300. + int valid_schemes = kValidUserScriptSchemes;
  6301. + // if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  6302. + // switches::kExtensionsOnChromeURLs)) {
  6303. + // valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  6304. + // }
  6305. + return valid_schemes;
  6306. +}
  6307. +
  6308. +UserScript::File::File(const base::FilePath& extension_root,
  6309. + const base::FilePath& relative_path,
  6310. + const GURL& url)
  6311. + : extension_root_(extension_root),
  6312. + relative_path_(relative_path),
  6313. + url_(url) {
  6314. +}
  6315. +
  6316. +UserScript::File::File() {}
  6317. +
  6318. +UserScript::File::File(const File& other)
  6319. + : extension_root_(other.extension_root_),
  6320. + relative_path_(other.relative_path_),
  6321. + url_(other.url_),
  6322. + external_content_(other.external_content_),
  6323. + content_(other.content_),
  6324. + key_(other.key_) {}
  6325. +
  6326. +UserScript::File::~File() {}
  6327. +
  6328. +UserScript::UserScript() = default;
  6329. +UserScript::~UserScript() = default;
  6330. +
  6331. +void UserScript::add_url_pattern(const URLPattern& pattern) {
  6332. + url_set_.AddPattern(pattern);
  6333. +}
  6334. +
  6335. +void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  6336. + exclude_url_set_.AddPattern(pattern);
  6337. +}
  6338. +
  6339. +bool UserScript::MatchesURL(const GURL& url) const {
  6340. + if (!url_set_.is_empty()) {
  6341. + if (!url_set_.MatchesURL(url)) {
  6342. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6343. + LOG(INFO) << "UserScripts: No Match for url_set";
  6344. + return false;
  6345. + }
  6346. + }
  6347. +
  6348. + if (!exclude_url_set_.is_empty()) {
  6349. + if (exclude_url_set_.MatchesURL(url)) {
  6350. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6351. + LOG(INFO) << "UserScripts: No Match for exclude_url_set";
  6352. + return false;
  6353. + }
  6354. + }
  6355. +
  6356. + if (!globs_.empty()) {
  6357. + if (!UrlMatchesGlobs(&globs_, url)) {
  6358. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6359. + LOG(INFO) << "UserScripts: No Match for globs";
  6360. + return false;
  6361. + }
  6362. + }
  6363. +
  6364. + if (!exclude_globs_.empty()) {
  6365. + if (UrlMatchesGlobs(&exclude_globs_, url)) {
  6366. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  6367. + LOG(INFO) << "UserScripts: No Match for exclude_globs";
  6368. + return false;
  6369. + }
  6370. + }
  6371. +
  6372. + return true;
  6373. +}
  6374. +
  6375. +bool UserScript::MatchesDocument(const GURL& effective_document_url,
  6376. + bool is_subframe) const {
  6377. + if (is_subframe && !match_all_frames())
  6378. + return false;
  6379. +
  6380. + return MatchesURL(effective_document_url);
  6381. +}
  6382. +
  6383. +void UserScript::File::Pickle(base::Pickle* pickle) const {
  6384. + pickle->WriteString(url_.spec());
  6385. + // Do not write path. It's not needed in the renderer.
  6386. + // Do not write content. It will be serialized by other means.
  6387. +}
  6388. +
  6389. +void UserScript::File::Unpickle(const base::Pickle& pickle,
  6390. + base::PickleIterator* iter) {
  6391. + // Read the url from the pickle.
  6392. + std::string url;
  6393. + CHECK(iter->ReadString(&url));
  6394. + set_url(GURL(url));
  6395. +}
  6396. +
  6397. +void UserScript::Pickle(base::Pickle* pickle) const {
  6398. + // Write the simple types to the pickle.
  6399. + pickle->WriteInt(run_location());
  6400. + pickle->WriteInt(user_script_id_);
  6401. + pickle->WriteBool(emulate_greasemonkey());
  6402. + pickle->WriteBool(match_all_frames());
  6403. + pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  6404. + pickle->WriteBool(is_incognito_enabled());
  6405. +
  6406. + PickleHostID(pickle, host_id_);
  6407. + pickle->WriteInt(consumer_instance_type());
  6408. + PickleGlobs(pickle, globs_);
  6409. + PickleGlobs(pickle, exclude_globs_);
  6410. + PickleURLPatternSet(pickle, url_set_);
  6411. + PickleURLPatternSet(pickle, exclude_url_set_);
  6412. + PickleScripts(pickle, js_scripts_);
  6413. + PickleScripts(pickle, css_scripts_);
  6414. +}
  6415. +
  6416. +void UserScript::PickleGlobs(base::Pickle* pickle,
  6417. + const std::vector<std::string>& globs) const {
  6418. + pickle->WriteUInt32(globs.size());
  6419. + for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  6420. + pickle->WriteString(*glob);
  6421. + }
  6422. +}
  6423. +
  6424. +void UserScript::PickleHostID(base::Pickle* pickle,
  6425. + const HostID& host_id) const {
  6426. + pickle->WriteInt(host_id.type());
  6427. + pickle->WriteString(host_id.id());
  6428. +}
  6429. +
  6430. +void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  6431. + const URLPatternSet& pattern_list) const {
  6432. + pickle->WriteUInt32(pattern_list.patterns().size());
  6433. + for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  6434. + ++pattern) {
  6435. + pickle->WriteInt(pattern->valid_schemes());
  6436. + pickle->WriteString(pattern->GetAsString());
  6437. + }
  6438. +}
  6439. +
  6440. +void UserScript::PickleScripts(base::Pickle* pickle,
  6441. + const FileList& scripts) const {
  6442. + pickle->WriteUInt32(scripts.size());
  6443. + for (const std::unique_ptr<File>& file : scripts)
  6444. + file->Pickle(pickle);
  6445. +}
  6446. +
  6447. +void UserScript::Unpickle(const base::Pickle& pickle,
  6448. + base::PickleIterator* iter) {
  6449. + // Read the run location.
  6450. + int run_location = 0;
  6451. + CHECK(iter->ReadInt(&run_location));
  6452. + CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
  6453. + run_location_ = static_cast<RunLocation>(run_location);
  6454. +
  6455. + CHECK(iter->ReadInt(&user_script_id_));
  6456. + CHECK(iter->ReadBool(&emulate_greasemonkey_));
  6457. + CHECK(iter->ReadBool(&match_all_frames_));
  6458. + int match_origin_as_fallback_int = 0;
  6459. + CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  6460. + match_origin_as_fallback_ =
  6461. + static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  6462. + CHECK(iter->ReadBool(&incognito_enabled_));
  6463. +
  6464. + UnpickleHostID(pickle, iter, &host_id_);
  6465. +
  6466. + int consumer_instance_type = 0;
  6467. + CHECK(iter->ReadInt(&consumer_instance_type));
  6468. + consumer_instance_type_ =
  6469. + static_cast<ConsumerInstanceType>(consumer_instance_type);
  6470. +
  6471. + UnpickleGlobs(pickle, iter, &globs_);
  6472. + UnpickleGlobs(pickle, iter, &exclude_globs_);
  6473. + UnpickleURLPatternSet(pickle, iter, &url_set_);
  6474. + UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  6475. + UnpickleScripts(pickle, iter, &js_scripts_);
  6476. + UnpickleScripts(pickle, iter, &css_scripts_);
  6477. +}
  6478. +
  6479. +void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  6480. + base::PickleIterator* iter,
  6481. + std::vector<std::string>* globs) {
  6482. + uint32_t num_globs = 0;
  6483. + CHECK(iter->ReadUInt32(&num_globs));
  6484. + globs->clear();
  6485. + for (uint32_t i = 0; i < num_globs; ++i) {
  6486. + std::string glob;
  6487. + CHECK(iter->ReadString(&glob));
  6488. + globs->push_back(glob);
  6489. + }
  6490. +}
  6491. +
  6492. +void UserScript::UnpickleHostID(const base::Pickle& pickle,
  6493. + base::PickleIterator* iter,
  6494. + HostID* host_id) {
  6495. + int type = 0;
  6496. + std::string id;
  6497. + CHECK(iter->ReadInt(&type));
  6498. + CHECK(iter->ReadString(&id));
  6499. + *host_id = HostID(static_cast<HostID::HostType>(type), id);
  6500. +}
  6501. +
  6502. +void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  6503. + base::PickleIterator* iter,
  6504. + URLPatternSet* pattern_list) {
  6505. + uint32_t num_patterns = 0;
  6506. + CHECK(iter->ReadUInt32(&num_patterns));
  6507. +
  6508. + pattern_list->ClearPatterns();
  6509. + for (uint32_t i = 0; i < num_patterns; ++i) {
  6510. + int valid_schemes;
  6511. + CHECK(iter->ReadInt(&valid_schemes));
  6512. +
  6513. + std::string pattern_str;
  6514. + CHECK(iter->ReadString(&pattern_str));
  6515. +
  6516. + URLPattern pattern(kValidUserScriptSchemes);
  6517. + URLPattern::ParseResult result = pattern.Parse(pattern_str);
  6518. + CHECK(URLPattern::ParseResult::kSuccess == result)
  6519. + << URLPattern::GetParseResultString(result) << " "
  6520. + << pattern_str.c_str();
  6521. +
  6522. + pattern.SetValidSchemes(valid_schemes);
  6523. + pattern_list->AddPattern(pattern);
  6524. + }
  6525. +}
  6526. +
  6527. +void UserScript::UnpickleScripts(const base::Pickle& pickle,
  6528. + base::PickleIterator* iter,
  6529. + FileList* scripts) {
  6530. + uint32_t num_files = 0;
  6531. + CHECK(iter->ReadUInt32(&num_files));
  6532. + scripts->clear();
  6533. + for (uint32_t i = 0; i < num_files; ++i) {
  6534. + std::unique_ptr<File> file(new File());
  6535. + file->Unpickle(pickle, iter);
  6536. + scripts->push_back(std::move(file));
  6537. + }
  6538. +}
  6539. +
  6540. +UserScriptIDPair::UserScriptIDPair(int id, const HostID& host_id)
  6541. + : id(id), host_id(host_id) {}
  6542. +
  6543. +UserScriptIDPair::UserScriptIDPair(int id) : id(id), host_id(HostID()) {}
  6544. +
  6545. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b) {
  6546. + return a.id < b.id;
  6547. +}
  6548. +
  6549. +} // namespace extensions
  6550. diff --git a/components/user_scripts/common/user_script.h b/components/user_scripts/common/user_script.h
  6551. new file mode 100755
  6552. --- /dev/null
  6553. +++ b/components/user_scripts/common/user_script.h
  6554. @@ -0,0 +1,403 @@
  6555. +// Copyright 2013 The Chromium Authors. All rights reserved.
  6556. +// Use of this source code is governed by a BSD-style license that can be
  6557. +// found in the LICENSE file.
  6558. +
  6559. +#ifndef USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6560. +#define USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6561. +
  6562. +#include <memory>
  6563. +#include <string>
  6564. +#include <vector>
  6565. +
  6566. +#include "base/files/file_path.h"
  6567. +#include "base/strings/string_piece.h"
  6568. +#include "script_constants.h"
  6569. +#include "host_id.h"
  6570. +#include "url_pattern.h"
  6571. +#include "url_pattern_set.h"
  6572. +#include "url/gurl.h"
  6573. +
  6574. +namespace base {
  6575. +class Pickle;
  6576. +class PickleIterator;
  6577. +}
  6578. +
  6579. +namespace user_scripts {
  6580. +
  6581. +// Represents a user script, either a standalone one, or one that is part of an
  6582. +// extension.
  6583. +class UserScript {
  6584. + public:
  6585. + // The file extension for standalone user scripts.
  6586. + static const char kFileExtension[];
  6587. +
  6588. + static int GenerateUserScriptID();
  6589. +
  6590. + // Check if a URL should be treated as a user script and converted to an
  6591. + // extension.
  6592. + static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
  6593. +
  6594. + // Get the valid user script schemes for the current process. If
  6595. + // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
  6596. + static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
  6597. +
  6598. + // TODO(rdevlin.cronin) This and RunLocation don't really belong here, since
  6599. + // they are used for more than UserScripts (e.g., tabs.executeScript()).
  6600. + // The type of injected script.
  6601. + enum InjectionType {
  6602. + // A content script specified in the extension's manifest.
  6603. + CONTENT_SCRIPT,
  6604. + // A script injected via, e.g. tabs.executeScript().
  6605. + //PROGRAMMATIC_SCRIPT
  6606. + };
  6607. + // The last type of injected script; used for enum verification in IPC.
  6608. + // Update this if you add more injected script types!
  6609. + static const InjectionType INJECTION_TYPE_LAST = CONTENT_SCRIPT/*PROGRAMMATIC_SCRIPT*/;
  6610. +
  6611. + // Locations that user scripts can be run inside the document.
  6612. + // The three run locations must strictly follow each other in both load order
  6613. + // (i.e., start *always* comes before end) and numerically, as we use
  6614. + // arithmetic checking (e.g., curr == last + 1). So, no bitmasks here!!
  6615. + enum RunLocation {
  6616. + UNDEFINED,
  6617. + DOCUMENT_START, // After the documentElement is created, but before
  6618. + // anything else happens.
  6619. + DOCUMENT_END, // After the entire document is parsed. Same as
  6620. + // DOMContentLoaded.
  6621. + DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
  6622. + // is "idle". Currently this uses the simple heuristic of:
  6623. + // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
  6624. + // particular injection point is guaranteed.
  6625. + RUN_DEFERRED, // The user script's injection was deferred for permissions
  6626. + // reasons, and was executed at a later time.
  6627. + BROWSER_DRIVEN, // The user script will be injected when triggered by an
  6628. + // IPC in the browser process.
  6629. + RUN_LOCATION_LAST // Leave this as the last item.
  6630. + };
  6631. +
  6632. + // Holds script file info.
  6633. + class File {
  6634. + public:
  6635. + File(const base::FilePath& extension_root,
  6636. + const base::FilePath& relative_path,
  6637. + const GURL& url);
  6638. + File();
  6639. + File(const File& other);
  6640. + ~File();
  6641. +
  6642. + const base::FilePath& extension_root() const { return extension_root_; }
  6643. + const base::FilePath& relative_path() const { return relative_path_; }
  6644. +
  6645. + const GURL& url() const { return url_; }
  6646. + void set_url(const GURL& url) { url_ = url; }
  6647. +
  6648. + // If external_content_ is set returns it as content otherwise it returns
  6649. + // content_
  6650. + const base::StringPiece GetContent() const {
  6651. + if (external_content_.data())
  6652. + return external_content_;
  6653. + else
  6654. + return content_;
  6655. + }
  6656. + void set_external_content(const base::StringPiece& content) {
  6657. + external_content_ = content;
  6658. + }
  6659. + void set_content(const base::StringPiece& content) {
  6660. + content_.assign(content.begin(), content.end());
  6661. + }
  6662. +
  6663. + const std::string& key() const { return key_; }
  6664. + void set_key(const std::string& key) {
  6665. + key_ = key;
  6666. + }
  6667. +
  6668. + // Serialization support. The content and FilePath members will not be
  6669. + // serialized!
  6670. + void Pickle(base::Pickle* pickle) const;
  6671. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6672. +
  6673. + private:
  6674. + // Where the script file lives on the disk. We keep the path split so that
  6675. + // it can be localized at will.
  6676. + base::FilePath extension_root_;
  6677. + base::FilePath relative_path_;
  6678. +
  6679. + // The url to this script file.
  6680. + GURL url_;
  6681. +
  6682. + // The script content. It can be set to either loaded_content_ or
  6683. + // externally allocated string.
  6684. + base::StringPiece external_content_;
  6685. +
  6686. + // Set when the content is loaded by LoadContent
  6687. + std::string content_;
  6688. +
  6689. + std::string key_;
  6690. + };
  6691. +
  6692. + using FileList = std::vector<std::unique_ptr<File>>;
  6693. +
  6694. + // Type of a API consumer instance that user scripts will be injected on.
  6695. + enum ConsumerInstanceType { TAB, WEBVIEW };
  6696. +
  6697. + // Constructor. Default the run location to document end, which is like
  6698. + // Greasemonkey and probably more useful for typical scripts.
  6699. + UserScript();
  6700. + ~UserScript();
  6701. +
  6702. + // Performs a copy of all fields except file contents.
  6703. + // static std::unique_ptr<UserScript> CopyMetadataFrom(const UserScript& other);
  6704. +
  6705. + const std::string& name_space() const { return name_space_; }
  6706. + void set_name_space(const std::string& name_space) {
  6707. + name_space_ = name_space;
  6708. + }
  6709. +
  6710. + const std::string& name() const { return name_; }
  6711. + void set_name(const std::string& name) { name_ = name; }
  6712. +
  6713. + const std::string& version() const { return version_; }
  6714. + void set_version(const std::string& version) {
  6715. + version_ = version;
  6716. + }
  6717. +
  6718. + const std::string& key() const { return key_; }
  6719. + void set_key(const std::string& key) {
  6720. + key_ = key;
  6721. + }
  6722. +
  6723. + const std::string& file_path() const { return file_path_; }
  6724. + void set_file_path(const std::string& file_path) {
  6725. + file_path_ = file_path;
  6726. + }
  6727. +
  6728. + const std::string& url_source() const { return url_source_; }
  6729. + void set_url_source(const std::string& url_source) {
  6730. + url_source_ = url_source;
  6731. + }
  6732. +
  6733. + const std::string& description() const { return description_; }
  6734. + void set_description(const std::string& description) {
  6735. + description_ = description;
  6736. + }
  6737. +
  6738. + const std::string& parser_error() const { return parser_error_; }
  6739. + void set_parser_error(const std::string& parser_error) {
  6740. + parser_error_ = parser_error;
  6741. + }
  6742. +
  6743. + bool force_disabled() const { return force_disabled_; }
  6744. + void set_force_disabled() {
  6745. + force_disabled_ = true;
  6746. + }
  6747. +
  6748. + // The place in the document to run the script.
  6749. + RunLocation run_location() const { return run_location_; }
  6750. + void set_run_location(RunLocation location) { run_location_ = location; }
  6751. +
  6752. + // Whether to emulate greasemonkey when running this script.
  6753. + bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
  6754. + void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
  6755. +
  6756. + // Whether to match all frames, or only the top one.
  6757. + bool match_all_frames() const { return match_all_frames_; }
  6758. + void set_match_all_frames(bool val) { match_all_frames_ = val; }
  6759. +
  6760. + // Whether to match the origin as a fallback if the URL cannot be used
  6761. + // directly.
  6762. + MatchOriginAsFallbackBehavior match_origin_as_fallback() const {
  6763. + return match_origin_as_fallback_;
  6764. + }
  6765. + void set_match_origin_as_fallback(MatchOriginAsFallbackBehavior val) {
  6766. + match_origin_as_fallback_ = val;
  6767. + }
  6768. +
  6769. + // The globs, if any, that determine which pages this script runs against.
  6770. + // These are only used with "standalone" Greasemonkey-like user scripts.
  6771. + const std::vector<std::string>& globs() const { return globs_; }
  6772. + void add_glob(const std::string& glob) { globs_.push_back(glob); }
  6773. + void clear_globs() { globs_.clear(); }
  6774. + const std::vector<std::string>& exclude_globs() const {
  6775. + return exclude_globs_;
  6776. + }
  6777. + void add_exclude_glob(const std::string& glob) {
  6778. + exclude_globs_.push_back(glob);
  6779. + }
  6780. + void clear_exclude_globs() { exclude_globs_.clear(); }
  6781. +
  6782. + // The URLPatterns, if any, that determine which pages this script runs
  6783. + // against.
  6784. + const URLPatternSet& url_patterns() const { return url_set_; }
  6785. + void add_url_pattern(const URLPattern& pattern);
  6786. + const URLPatternSet& exclude_url_patterns() const {
  6787. + return exclude_url_set_;
  6788. + }
  6789. + void add_exclude_url_pattern(const URLPattern& pattern);
  6790. +
  6791. + // List of js scripts for this user script
  6792. + FileList& js_scripts() { return js_scripts_; }
  6793. + const FileList& js_scripts() const { return js_scripts_; }
  6794. +
  6795. + // List of css scripts for this user script
  6796. + FileList& css_scripts() { return css_scripts_; }
  6797. + const FileList& css_scripts() const { return css_scripts_; }
  6798. +
  6799. + const std::string& extension_id() const { return host_id_.id(); }
  6800. +
  6801. + const HostID& host_id() const { return host_id_; }
  6802. + void set_host_id(const HostID& host_id) { host_id_ = host_id; }
  6803. +
  6804. + const ConsumerInstanceType& consumer_instance_type() const {
  6805. + return consumer_instance_type_;
  6806. + }
  6807. + void set_consumer_instance_type(
  6808. + const ConsumerInstanceType& consumer_instance_type) {
  6809. + consumer_instance_type_ = consumer_instance_type;
  6810. + }
  6811. +
  6812. + int id() const { return user_script_id_; }
  6813. + void set_id(int id) { user_script_id_ = id; }
  6814. +
  6815. + // TODO(lazyboy): Incognito information is extension specific, it doesn't
  6816. + // belong here. We should be able to determine this in the renderer/ where it
  6817. + // is used.
  6818. + bool is_incognito_enabled() const { return incognito_enabled_; }
  6819. + void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
  6820. +
  6821. + // Returns true if the script should be applied to the specified URL, false
  6822. + // otherwise.
  6823. + bool MatchesURL(const GURL& url) const;
  6824. +
  6825. + // Returns true if the script should be applied to the given
  6826. + // |effective_document_url|. It is the caller's responsibility to calculate
  6827. + // |effective_document_url| based on match_origin_as_fallback().
  6828. + bool MatchesDocument(const GURL& effective_document_url,
  6829. + bool is_subframe) const;
  6830. +
  6831. + // Serializes the UserScript into a pickle. The content of the scripts and
  6832. + // paths to UserScript::Files will not be serialized!
  6833. + void Pickle(base::Pickle* pickle) const;
  6834. +
  6835. + // Deserializes the script from a pickle. Note that this always succeeds
  6836. + // because presumably we were the one that pickled it, and we did it
  6837. + // correctly.
  6838. + void Unpickle(const base::Pickle& pickle, base::PickleIterator* iter);
  6839. +
  6840. + private:
  6841. + // base::Pickle helper functions used to pickle the individual types of
  6842. + // components.
  6843. + void PickleGlobs(base::Pickle* pickle,
  6844. + const std::vector<std::string>& globs) const;
  6845. + void PickleHostID(base::Pickle* pickle, const HostID& host_id) const;
  6846. + void PickleURLPatternSet(base::Pickle* pickle,
  6847. + const URLPatternSet& pattern_list) const;
  6848. + void PickleScripts(base::Pickle* pickle, const FileList& scripts) const;
  6849. +
  6850. + // Unpickle helper functions used to unpickle individual types of components.
  6851. + void UnpickleGlobs(const base::Pickle& pickle,
  6852. + base::PickleIterator* iter,
  6853. + std::vector<std::string>* globs);
  6854. + void UnpickleHostID(const base::Pickle& pickle,
  6855. + base::PickleIterator* iter,
  6856. + HostID* host_id);
  6857. + void UnpickleURLPatternSet(const base::Pickle& pickle,
  6858. + base::PickleIterator* iter,
  6859. + URLPatternSet* pattern_list);
  6860. + void UnpickleScripts(const base::Pickle& pickle,
  6861. + base::PickleIterator* iter,
  6862. + FileList* scripts);
  6863. +
  6864. + // The location to run the script inside the document.
  6865. + RunLocation run_location_ = DOCUMENT_IDLE;
  6866. +
  6867. + // The namespace of the script. This is used by Greasemonkey in the same way
  6868. + // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
  6869. + std::string name_space_;
  6870. +
  6871. + // The script's name. Only used when parsing Greasemonkey-style scripts.
  6872. + std::string name_;
  6873. +
  6874. + // A longer description. Only used when parsing Greasemonkey-style scripts.
  6875. + std::string description_;
  6876. +
  6877. + // Parser error to show to user
  6878. + std::string parser_error_;
  6879. +
  6880. + // A version number of the script. Only used when parsing Greasemonkey-style
  6881. + // scripts.
  6882. + std::string version_;
  6883. +
  6884. + // Greasemonkey-style globs that determine pages to inject the script into.
  6885. + // These are only used with standalone scripts.
  6886. + std::vector<std::string> globs_;
  6887. + std::vector<std::string> exclude_globs_;
  6888. +
  6889. + // URLPatterns that determine pages to inject the script into. These are
  6890. + // only used with scripts that are part of extensions.
  6891. + URLPatternSet url_set_;
  6892. + URLPatternSet exclude_url_set_;
  6893. +
  6894. + // List of js scripts defined in content_scripts
  6895. + FileList js_scripts_;
  6896. +
  6897. + // List of css scripts defined in content_scripts
  6898. + FileList css_scripts_;
  6899. +
  6900. + // internal key of scripts
  6901. + std::string key_;
  6902. +
  6903. + std::string file_path_;
  6904. +
  6905. + // url source of script
  6906. + std::string url_source_;
  6907. +
  6908. + // The ID of the host this script is a part of. The |ID| of the
  6909. + // |host_id| can be empty if the script is a "standlone" user script.
  6910. + HostID host_id_;
  6911. +
  6912. + // The type of the consumer instance that the script will be injected.
  6913. + ConsumerInstanceType consumer_instance_type_ = TAB;
  6914. +
  6915. + // The globally-unique id associated with this user script. -1 indicates
  6916. + // "invalid".
  6917. + int user_script_id_ = -1;
  6918. +
  6919. + // Whether we should try to emulate Greasemonkey's APIs when running this
  6920. + // script.
  6921. + bool emulate_greasemonkey_ = false;
  6922. +
  6923. + // Whether the user script should run in all frames, or only just the top one.
  6924. + bool match_all_frames_ = false;
  6925. +
  6926. + // Whether the user script should run in frames whose initiator / precursor
  6927. + // origin matches a match pattern, if an appropriate URL cannot be found for
  6928. + // the frame for matching purposes, such as in the case of about:, data:, and
  6929. + // other schemes.
  6930. + MatchOriginAsFallbackBehavior match_origin_as_fallback_ =
  6931. + MatchOriginAsFallbackBehavior::kNever;
  6932. +
  6933. + // True if the script should be injected into an incognito tab.
  6934. + bool incognito_enabled_ = false;
  6935. +
  6936. + // Script cannot be enabled
  6937. + bool force_disabled_ = false;
  6938. +
  6939. + DISALLOW_COPY_AND_ASSIGN(UserScript);
  6940. +};
  6941. +
  6942. +// Information we need while removing scripts from a UserScriptLoader.
  6943. +struct UserScriptIDPair {
  6944. + UserScriptIDPair(int id, const HostID& host_id);
  6945. + explicit UserScriptIDPair(int id);
  6946. +
  6947. + int id;
  6948. + HostID host_id;
  6949. +};
  6950. +
  6951. +bool operator<(const UserScriptIDPair& a, const UserScriptIDPair& b);
  6952. +
  6953. +using UserScriptList = std::vector<std::unique_ptr<UserScript>>;
  6954. +
  6955. +} // namespace extensions
  6956. +
  6957. +#endif // USERSCRIPTS_COMMON_USER_SCRIPT_H_
  6958. diff --git a/components/user_scripts/common/user_scripts_features.cc b/components/user_scripts/common/user_scripts_features.cc
  6959. new file mode 100644
  6960. --- /dev/null
  6961. +++ b/components/user_scripts/common/user_scripts_features.cc
  6962. @@ -0,0 +1,32 @@
  6963. +/*
  6964. + This file is part of Bromite.
  6965. +
  6966. + Bromite is free software: you can redistribute it and/or modify
  6967. + it under the terms of the GNU General Public License as published by
  6968. + the Free Software Foundation, either version 3 of the License, or
  6969. + (at your option) any later version.
  6970. +
  6971. + Bromite is distributed in the hope that it will be useful,
  6972. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  6973. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  6974. + GNU General Public License for more details.
  6975. +
  6976. + You should have received a copy of the GNU General Public License
  6977. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  6978. +*/
  6979. +
  6980. +#include "user_scripts_features.h"
  6981. +
  6982. +#include "build/build_config.h"
  6983. +
  6984. +namespace user_scripts {
  6985. +
  6986. +namespace features {
  6987. +
  6988. +const base::Feature kEnableLoggingUserScripts =
  6989. + {"EnableLoggingUserScripts",
  6990. + base::FEATURE_DISABLED_BY_DEFAULT};
  6991. +
  6992. +}
  6993. +
  6994. +}
  6995. \ No newline at end of file
  6996. diff --git a/components/user_scripts/common/user_scripts_features.h b/components/user_scripts/common/user_scripts_features.h
  6997. new file mode 100644
  6998. --- /dev/null
  6999. +++ b/components/user_scripts/common/user_scripts_features.h
  7000. @@ -0,0 +1,34 @@
  7001. +/*
  7002. + This file is part of Bromite.
  7003. +
  7004. + Bromite is free software: you can redistribute it and/or modify
  7005. + it under the terms of the GNU General Public License as published by
  7006. + the Free Software Foundation, either version 3 of the License, or
  7007. + (at your option) any later version.
  7008. +
  7009. + Bromite is distributed in the hope that it will be useful,
  7010. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  7011. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  7012. + GNU General Public License for more details.
  7013. +
  7014. + You should have received a copy of the GNU General Public License
  7015. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  7016. +*/
  7017. +
  7018. +#ifndef USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7019. +#define USERSCRIPTS_COMMON_USERSCRIPTS_FEATURES_H_
  7020. +
  7021. +// This file defines all the base::FeatureList features for the Password Manager
  7022. +// module.
  7023. +
  7024. +#include "base/feature_list.h"
  7025. +
  7026. +namespace user_scripts {
  7027. +
  7028. +namespace features {
  7029. + extern const base::Feature kEnableLoggingUserScripts;
  7030. +}
  7031. +
  7032. +}
  7033. +
  7034. +#endif
  7035. \ No newline at end of file
  7036. diff --git a/components/user_scripts/common/view_type.cc b/components/user_scripts/common/view_type.cc
  7037. new file mode 100755
  7038. --- /dev/null
  7039. +++ b/components/user_scripts/common/view_type.cc
  7040. @@ -0,0 +1,39 @@
  7041. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7042. +// Use of this source code is governed by a BSD-style license that can be
  7043. +// found in the LICENSE file.
  7044. +
  7045. +#include "view_type.h"
  7046. +
  7047. +#include "base/strings/string_piece.h"
  7048. +
  7049. +namespace user_scripts {
  7050. +
  7051. +bool GetViewTypeFromString(const std::string& view_type,
  7052. + ViewType* view_type_out) {
  7053. + // TODO(devlin): This map doesn't contain the following values:
  7054. + // - VIEW_TYPE_BACKGROUND_CONTENTS
  7055. + // - VIEW_TYPE_COMPONENT
  7056. + // - VIEW_TYPE_EXTENSION_GUEST
  7057. + // Why? Is it just because we don't expose those types to JS?
  7058. + static const struct {
  7059. + ViewType type;
  7060. + base::StringPiece name;
  7061. + } constexpr kTypeMap[] = {
  7062. + // {VIEW_TYPE_APP_WINDOW, "APP_WINDOW"},
  7063. + // {VIEW_TYPE_EXTENSION_BACKGROUND_PAGE, "BACKGROUND"},
  7064. + // {VIEW_TYPE_EXTENSION_DIALOG, "EXTENSION_DIALOG"},
  7065. + // {VIEW_TYPE_EXTENSION_POPUP, "POPUP"},
  7066. + {VIEW_TYPE_TAB_CONTENTS, "TAB"},
  7067. + };
  7068. +
  7069. + for (const auto& entry : kTypeMap) {
  7070. + if (entry.name == view_type) {
  7071. + *view_type_out = entry.type;
  7072. + return true;
  7073. + }
  7074. + }
  7075. +
  7076. + return false;
  7077. +}
  7078. +
  7079. +} // namespace extensions
  7080. diff --git a/components/user_scripts/common/view_type.h b/components/user_scripts/common/view_type.h
  7081. new file mode 100755
  7082. --- /dev/null
  7083. +++ b/components/user_scripts/common/view_type.h
  7084. @@ -0,0 +1,48 @@
  7085. +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
  7086. +// Use of this source code is governed by a BSD-style license that can be
  7087. +// found in the LICENSE file.
  7088. +
  7089. +#ifndef USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7090. +#define USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7091. +
  7092. +#include <string>
  7093. +
  7094. +namespace user_scripts {
  7095. +
  7096. +// Icky RTTI used by a few systems to distinguish the host type of a given
  7097. +// WebContents.
  7098. +//
  7099. +// Do not change or reuse the the entry values in this list as this is used in
  7100. +// ExtensionViewType enum in tools/metrics/histograms/enums.xml.
  7101. +//
  7102. +// TODO(aa): Remove this and teach those systems to keep track of their own
  7103. +// data.
  7104. +enum ViewType {
  7105. + VIEW_TYPE_INVALID = 0,
  7106. + // VIEW_TYPE_APP_WINDOW = 1,
  7107. + // VIEW_TYPE_BACKGROUND_CONTENTS = 2,
  7108. +
  7109. + // // For custom parts of Chrome if no other type applies.
  7110. + // VIEW_TYPE_COMPONENT = 3,
  7111. +
  7112. + // VIEW_TYPE_EXTENSION_BACKGROUND_PAGE = 4,
  7113. + // VIEW_TYPE_EXTENSION_DIALOG = 5,
  7114. + // VIEW_TYPE_EXTENSION_GUEST = 6,
  7115. + // VIEW_TYPE_EXTENSION_POPUP = 7,
  7116. +
  7117. + // Panels were removed in https://crbug.com/571511.
  7118. + // DEPRECATED_VIEW_TYPE_PANEL = 8,
  7119. +
  7120. + VIEW_TYPE_TAB_CONTENTS = 9,
  7121. +
  7122. + VIEW_TYPE_LAST = VIEW_TYPE_TAB_CONTENTS
  7123. +};
  7124. +
  7125. +// Matches the |view_type| to the corresponding ViewType, and populates
  7126. +// |view_type_out|. Returns true if a match is found.
  7127. +bool GetViewTypeFromString(const std::string& view_type,
  7128. + ViewType* view_type_out);
  7129. +
  7130. +} // namespace extensions
  7131. +
  7132. +#endif // USERSCRIPTS_COMMON_VIEW_TYPE_H_
  7133. diff --git a/components/user_scripts/renderer/BUILD.gn b/components/user_scripts/renderer/BUILD.gn
  7134. new file mode 100755
  7135. --- /dev/null
  7136. +++ b/components/user_scripts/renderer/BUILD.gn
  7137. @@ -0,0 +1,67 @@
  7138. +# Copyright 2015 The Chromium Authors. All rights reserved.
  7139. +# Use of this source code is governed by a BSD-style license that can be
  7140. +# found in the LICENSE file.
  7141. +
  7142. +import("//tools/grit/grit_rule.gni")
  7143. +import("//tools/grit/repack.gni")
  7144. +
  7145. +group("user_scripts_resources") {
  7146. + public_deps = [
  7147. + ":user_scripts_renderer_resources",
  7148. + ]
  7149. +}
  7150. +
  7151. +grit("user_scripts_renderer_resources") {
  7152. + source = "resources/user_scripts_renderer_resources.grd"
  7153. + outputs = [
  7154. + "grit/user_scripts_renderer_resources.h",
  7155. + "user_scripts_renderer_resources.pak",
  7156. + ]
  7157. + grit_flags = [
  7158. + "-E",
  7159. + "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
  7160. + ]
  7161. +}
  7162. +
  7163. +static_library("renderer") {
  7164. + sources = [
  7165. + "extension_frame_helper.cc",
  7166. + "extension_frame_helper.h",
  7167. + "injection_host.cc",
  7168. + "injection_host.h",
  7169. + "script_injection_manager.cc",
  7170. + "script_injection_manager.h",
  7171. + "script_injection_callback.cc",
  7172. + "script_injection_callback.h",
  7173. + "script_injection.cc",
  7174. + "script_injection.h",
  7175. + "script_injector.h",
  7176. + "script_context.cc",
  7177. + "script_context.h",
  7178. + "scripts_run_info.cc",
  7179. + "scripts_run_info.h",
  7180. + "user_script_injector.cc",
  7181. + "user_script_injector.h",
  7182. + "user_script_set_manager.cc",
  7183. + "user_script_set_manager.h",
  7184. + "user_script_set.cc",
  7185. + "user_script_set.h",
  7186. + "user_scripts_dispatcher.cc",
  7187. + "user_scripts_dispatcher.h",
  7188. + "user_scripts_renderer_client.cc",
  7189. + "user_scripts_renderer_client.h",
  7190. + "web_ui_injection_host.cc",
  7191. + "web_ui_injection_host.h",
  7192. + ]
  7193. +
  7194. + deps = [
  7195. + ":user_scripts_resources",
  7196. + "//base",
  7197. + "//content/public/common",
  7198. + "//content/public/renderer",
  7199. + "//components/user_scripts/common",
  7200. + "//mojo/public/cpp/bindings",
  7201. + "//third_party/blink/public:blink_headers",
  7202. + "//v8",
  7203. + ]
  7204. +}
  7205. diff --git a/components/user_scripts/renderer/extension_frame_helper.cc b/components/user_scripts/renderer/extension_frame_helper.cc
  7206. new file mode 100755
  7207. --- /dev/null
  7208. +++ b/components/user_scripts/renderer/extension_frame_helper.cc
  7209. @@ -0,0 +1,96 @@
  7210. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7211. +// Use of this source code is governed by a BSD-style license that can be
  7212. +// found in the LICENSE file.
  7213. +
  7214. +#include "extension_frame_helper.h"
  7215. +
  7216. +#include <set>
  7217. +
  7218. +#include "base/metrics/histogram_macros.h"
  7219. +#include "base/strings/string_util.h"
  7220. +#include "base/timer/elapsed_timer.h"
  7221. +#include "content/public/renderer/render_frame.h"
  7222. +#include "content/public/renderer/render_view.h"
  7223. +#include "../common/constants.h"
  7224. +#include "third_party/blink/public/platform/web_security_origin.h"
  7225. +#include "third_party/blink/public/web/web_console_message.h"
  7226. +#include "third_party/blink/public/web/web_document.h"
  7227. +#include "third_party/blink/public/web/web_document_loader.h"
  7228. +#include "third_party/blink/public/web/web_local_frame.h"
  7229. +#include "third_party/blink/public/web/web_settings.h"
  7230. +#include "third_party/blink/public/web/web_view.h"
  7231. +
  7232. +namespace user_scripts {
  7233. +
  7234. +namespace {
  7235. +
  7236. +base::LazyInstance<std::set<const ExtensionFrameHelper*>>::DestructorAtExit
  7237. + g_frame_helpers = LAZY_INSTANCE_INITIALIZER;
  7238. +
  7239. +// Runs every callback in |callbacks_to_be_run_and_cleared| while |frame_helper|
  7240. +// is valid, and clears |callbacks_to_be_run_and_cleared|.
  7241. +void RunCallbacksWhileFrameIsValid(
  7242. + base::WeakPtr<ExtensionFrameHelper> frame_helper,
  7243. + std::vector<base::OnceClosure>* callbacks_to_be_run_and_cleared) {
  7244. + // The JavaScript code can cause re-entrancy. To avoid a deadlock, don't run
  7245. + // callbacks that are added during the iteration.
  7246. + std::vector<base::OnceClosure> callbacks;
  7247. + callbacks_to_be_run_and_cleared->swap(callbacks);
  7248. + for (auto& callback : callbacks) {
  7249. + std::move(callback).Run();
  7250. + if (!frame_helper.get())
  7251. + return; // Frame and ExtensionFrameHelper invalidated by callback.
  7252. + }
  7253. +}
  7254. +
  7255. +} // namespace
  7256. +
  7257. +ExtensionFrameHelper::ExtensionFrameHelper(content::RenderFrame* render_frame)
  7258. + : content::RenderFrameObserver(render_frame),
  7259. + content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
  7260. + tab_id_(-1) {
  7261. + g_frame_helpers.Get().insert(this);
  7262. +}
  7263. +
  7264. +ExtensionFrameHelper::~ExtensionFrameHelper() {
  7265. + g_frame_helpers.Get().erase(this);
  7266. +}
  7267. +
  7268. +void ExtensionFrameHelper::ScheduleAtDocumentStart(
  7269. + base::OnceClosure callback) {
  7270. + document_element_created_callbacks_.push_back(std::move(callback));
  7271. +}
  7272. +
  7273. +void ExtensionFrameHelper::ScheduleAtDocumentEnd(
  7274. + base::OnceClosure callback) {
  7275. + document_load_finished_callbacks_.push_back(std::move(callback));
  7276. +}
  7277. +
  7278. +void ExtensionFrameHelper::ScheduleAtDocumentIdle(
  7279. + base::OnceClosure callback) {
  7280. + document_idle_callbacks_.push_back(std::move(callback));
  7281. +}
  7282. +
  7283. +void ExtensionFrameHelper::RunScriptsAtDocumentStart() {
  7284. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7285. + &document_element_created_callbacks_);
  7286. + // |this| might be dead by now.
  7287. +}
  7288. +
  7289. +void ExtensionFrameHelper::RunScriptsAtDocumentEnd() {
  7290. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7291. + &document_load_finished_callbacks_);
  7292. + // |this| might be dead by now.
  7293. +}
  7294. +
  7295. +void ExtensionFrameHelper::RunScriptsAtDocumentIdle() {
  7296. + RunCallbacksWhileFrameIsValid(weak_ptr_factory_.GetWeakPtr(),
  7297. + &document_idle_callbacks_);
  7298. + // |this| might be dead by now.
  7299. +}
  7300. +
  7301. +void ExtensionFrameHelper::OnDestruct() {
  7302. + delete this;
  7303. +}
  7304. +
  7305. +} // namespace user_scripts
  7306. diff --git a/components/user_scripts/renderer/extension_frame_helper.h b/components/user_scripts/renderer/extension_frame_helper.h
  7307. new file mode 100755
  7308. --- /dev/null
  7309. +++ b/components/user_scripts/renderer/extension_frame_helper.h
  7310. @@ -0,0 +1,92 @@
  7311. +// Copyright 2013 The Chromium Authors. All rights reserved.
  7312. +// Use of this source code is governed by a BSD-style license that can be
  7313. +// found in the LICENSE file.
  7314. +
  7315. +#ifndef USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7316. +#define USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7317. +
  7318. +#include <string>
  7319. +#include <vector>
  7320. +
  7321. +#include "base/callback_forward.h"
  7322. +#include "base/macros.h"
  7323. +#include "base/memory/weak_ptr.h"
  7324. +#include "content/public/renderer/render_frame_observer.h"
  7325. +#include "content/public/renderer/render_frame_observer_tracker.h"
  7326. +#include "../common/view_type.h"
  7327. +#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
  7328. +#include "v8/include/v8.h"
  7329. +
  7330. +struct ExtensionMsg_ExternalConnectionInfo;
  7331. +struct ExtensionMsg_TabConnectionInfo;
  7332. +
  7333. +namespace base {
  7334. +class ListValue;
  7335. +}
  7336. +
  7337. +namespace user_scripts {
  7338. +
  7339. +class Dispatcher;
  7340. +struct Message;
  7341. +struct PortId;
  7342. +class ScriptContext;
  7343. +
  7344. +// RenderFrame-level plumbing for extension features.
  7345. +class ExtensionFrameHelper
  7346. + : public content::RenderFrameObserver,
  7347. + public content::RenderFrameObserverTracker<ExtensionFrameHelper> {
  7348. + public:
  7349. + ExtensionFrameHelper(content::RenderFrame* render_frame /*,
  7350. + Dispatcher* extension_dispatcher*/);
  7351. + ~ExtensionFrameHelper() override;
  7352. +
  7353. + int tab_id() const { return tab_id_; }
  7354. +
  7355. + // Called when the document element has been inserted in this frame. This
  7356. + // method may invoke untrusted JavaScript code that invalidate the frame and
  7357. + // this ExtensionFrameHelper.
  7358. + void RunScriptsAtDocumentStart();
  7359. +
  7360. + // Called after the DOMContentLoaded event has fired.
  7361. + void RunScriptsAtDocumentEnd();
  7362. +
  7363. + // Called before the window.onload event is fired.
  7364. + void RunScriptsAtDocumentIdle();
  7365. +
  7366. + // Schedule a callback, to be run at the next RunScriptsAtDocumentStart
  7367. + // notification. Only call this when you are certain that there will be such a
  7368. + // notification, e.g. from RenderFrameObserver::DidCreateDocumentElement.
  7369. + // Otherwise the callback is never invoked, or invoked for a document that you
  7370. + // were not expecting.
  7371. + void ScheduleAtDocumentStart(base::OnceClosure callback);
  7372. +
  7373. + // Schedule a callback, to be run at the next RunScriptsAtDocumentEnd call.
  7374. + void ScheduleAtDocumentEnd(base::OnceClosure callback);
  7375. +
  7376. + // Schedule a callback, to be run at the next RunScriptsAtDocumentIdle call.
  7377. + void ScheduleAtDocumentIdle(base::OnceClosure callback);
  7378. +
  7379. + private:
  7380. +
  7381. + void OnDestruct() override;
  7382. +
  7383. + // The id of the tab the render frame is attached to.
  7384. + int tab_id_;
  7385. +
  7386. + // Callbacks to be run at the next RunScriptsAtDocumentStart notification.
  7387. + std::vector<base::OnceClosure> document_element_created_callbacks_;
  7388. +
  7389. + // Callbacks to be run at the next RunScriptsAtDocumentEnd notification.
  7390. + std::vector<base::OnceClosure> document_load_finished_callbacks_;
  7391. +
  7392. + // Callbacks to be run at the next RunScriptsAtDocumentIdle notification.
  7393. + std::vector<base::OnceClosure> document_idle_callbacks_;
  7394. +
  7395. + base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
  7396. +
  7397. + DISALLOW_COPY_AND_ASSIGN(ExtensionFrameHelper);
  7398. +};
  7399. +
  7400. +} // namespace extensions
  7401. +
  7402. +#endif // USERSCRIPTS_RENDERER_EXTENSION_FRAME_HELPER_H_
  7403. diff --git a/components/user_scripts/renderer/injection_host.cc b/components/user_scripts/renderer/injection_host.cc
  7404. new file mode 100755
  7405. --- /dev/null
  7406. +++ b/components/user_scripts/renderer/injection_host.cc
  7407. @@ -0,0 +1,12 @@
  7408. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7409. +// Use of this source code is governed by a BSD-style license that can be
  7410. +// found in the LICENSE file.
  7411. +
  7412. +#include "injection_host.h"
  7413. +
  7414. +InjectionHost::InjectionHost(const HostID& host_id) :
  7415. + id_(host_id) {
  7416. +}
  7417. +
  7418. +InjectionHost::~InjectionHost() {
  7419. +}
  7420. diff --git a/components/user_scripts/renderer/injection_host.h b/components/user_scripts/renderer/injection_host.h
  7421. new file mode 100755
  7422. --- /dev/null
  7423. +++ b/components/user_scripts/renderer/injection_host.h
  7424. @@ -0,0 +1,42 @@
  7425. +// Copyright 2015 The Chromium Authors. All rights reserved.
  7426. +// Use of this source code is governed by a BSD-style license that can be
  7427. +// found in the LICENSE file.
  7428. +
  7429. +#ifndef USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7430. +#define USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7431. +
  7432. +#include "base/macros.h"
  7433. +#include "../common/host_id.h"
  7434. +#include "url/gurl.h"
  7435. +
  7436. +namespace content {
  7437. +class RenderFrame;
  7438. +}
  7439. +
  7440. +// An interface for all kinds of hosts who own user scripts.
  7441. +class InjectionHost {
  7442. + public:
  7443. + InjectionHost(const HostID& host_id);
  7444. + virtual ~InjectionHost();
  7445. +
  7446. + // Returns the CSP to be used for the isolated world. Currently this only
  7447. + // bypasses the main world CSP. If null is returned, the main world CSP is not
  7448. + // bypassed.
  7449. + virtual const std::string* GetContentSecurityPolicy() const = 0;
  7450. +
  7451. + // The base url for the host.
  7452. + virtual const GURL& url() const = 0;
  7453. +
  7454. + // The human-readable name of the host.
  7455. + virtual const std::string& name() const = 0;
  7456. +
  7457. + const HostID& id() const { return id_; }
  7458. +
  7459. + private:
  7460. + // The ID of the host.
  7461. + HostID id_;
  7462. +
  7463. + DISALLOW_COPY_AND_ASSIGN(InjectionHost);
  7464. +};
  7465. +
  7466. +#endif // USERSCRIPTS_RENDERER_INJECTION_HOST_H_
  7467. diff --git a/components/user_scripts/renderer/resources/greasemonkey_api.js b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7468. new file mode 100755
  7469. --- /dev/null
  7470. +++ b/components/user_scripts/renderer/resources/greasemonkey_api.js
  7471. @@ -0,0 +1,82 @@
  7472. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7473. +// Use of this source code is governed by a BSD-style license that can be
  7474. +// found in the LICENSE file.
  7475. +
  7476. +// -----------------------------------------------------------------------------
  7477. +// NOTE: If you change this file you need to touch renderer_resources.grd to
  7478. +// have your change take effect.
  7479. +// -----------------------------------------------------------------------------
  7480. +
  7481. +// Partial implementation of the Greasemonkey API, see:
  7482. +// http://wiki.greasespot.net/Greasemonkey_Manual:APIs
  7483. +
  7484. +function GM_addStyle(css) {
  7485. + var parent = document.getElementsByTagName("head")[0];
  7486. + if (!parent) {
  7487. + parent = document.documentElement;
  7488. + }
  7489. + var style = document.createElement("style");
  7490. + style.type = "text/css";
  7491. + var textNode = document.createTextNode(css);
  7492. + style.appendChild(textNode);
  7493. + parent.appendChild(style);
  7494. +}
  7495. +
  7496. +function GM_xmlhttpRequest(details) {
  7497. + function setupEvent(xhr, url, eventName, callback) {
  7498. + xhr[eventName] = function () {
  7499. + var isComplete = xhr.readyState == 4;
  7500. + var responseState = {
  7501. + responseText: xhr.responseText,
  7502. + readyState: xhr.readyState,
  7503. + responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
  7504. + status: isComplete ? xhr.status : 0,
  7505. + statusText: isComplete ? xhr.statusText : "",
  7506. + finalUrl: isComplete ? url : ""
  7507. + };
  7508. + callback(responseState);
  7509. + };
  7510. + }
  7511. +
  7512. + var xhr = new XMLHttpRequest();
  7513. + var eventNames = ["onload", "onerror", "onreadystatechange"];
  7514. + for (var i = 0; i < eventNames.length; i++ ) {
  7515. + var eventName = eventNames[i];
  7516. + if (eventName in details) {
  7517. + setupEvent(xhr, details.url, eventName, details[eventName]);
  7518. + }
  7519. + }
  7520. +
  7521. + xhr.open(details.method, details.url);
  7522. +
  7523. + if (details.overrideMimeType) {
  7524. + xhr.overrideMimeType(details.overrideMimeType);
  7525. + }
  7526. + if (details.headers) {
  7527. + for (var header in details.headers) {
  7528. + xhr.setRequestHeader(header, details.headers[header]);
  7529. + }
  7530. + }
  7531. + xhr.send(details.data ? details.data : null);
  7532. +}
  7533. +
  7534. +function GM_openInTab(url) {
  7535. + window.open(url, "");
  7536. +}
  7537. +
  7538. +function GM_log(message) {
  7539. + window.console.log(message);
  7540. +}
  7541. +
  7542. +(function() {
  7543. + function generateGreasemonkeyStub(name) {
  7544. + return function() {
  7545. + console.log("%s is not supported.", name);
  7546. + };
  7547. + }
  7548. +
  7549. + var apis = ["GM_getValue", "GM_setValue", "GM_registerMenuCommand"];
  7550. + for (var i = 0, api; api = apis[i]; i++) {
  7551. + window[api] = generateGreasemonkeyStub(api);
  7552. + }
  7553. +})();
  7554. diff --git a/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7555. new file mode 100755
  7556. --- /dev/null
  7557. +++ b/components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd
  7558. @@ -0,0 +1,14 @@
  7559. +<?xml version="1.0" encoding="UTF-8"?>
  7560. +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
  7561. + <outputs>
  7562. + <output filename="grit/user_scripts_renderer_resources.h" type="rc_header">
  7563. + <emit emit_type='prepend'></emit>
  7564. + </output>
  7565. + <output filename="user_scripts_renderer_resources.pak" type="data_package" />
  7566. + </outputs>
  7567. + <release seq="1">
  7568. + <includes>
  7569. + <include name="IDR_GREASEMONKEY_API_JS" file="greasemonkey_api.js" type="BINDATA" />
  7570. + </includes>
  7571. + </release>
  7572. +</grit>
  7573. diff --git a/components/user_scripts/renderer/script_context.cc b/components/user_scripts/renderer/script_context.cc
  7574. new file mode 100755
  7575. --- /dev/null
  7576. +++ b/components/user_scripts/renderer/script_context.cc
  7577. @@ -0,0 +1,213 @@
  7578. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7579. +// Use of this source code is governed by a BSD-style license that can be
  7580. +// found in the LICENSE file.
  7581. +
  7582. +#include "script_context.h"
  7583. +
  7584. +#include "base/command_line.h"
  7585. +#include "base/containers/flat_set.h"
  7586. +#include "base/logging.h"
  7587. +#include "base/stl_util.h"
  7588. +#include "base/strings/string_util.h"
  7589. +#include "base/strings/stringprintf.h"
  7590. +#include "base/values.h"
  7591. +#include "content/public/common/content_switches.h"
  7592. +#include "content/public/common/url_constants.h"
  7593. +#include "content/public/renderer/render_frame.h"
  7594. +#include "../common/constants.h"
  7595. +#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
  7596. +#include "third_party/blink/public/platform/web_security_origin.h"
  7597. +#include "third_party/blink/public/web/web_document.h"
  7598. +#include "third_party/blink/public/web/web_document_loader.h"
  7599. +#include "third_party/blink/public/web/web_local_frame.h"
  7600. +#include "third_party/blink/public/web/web_navigation_params.h"
  7601. +#include "v8/include/v8.h"
  7602. +
  7603. +namespace user_scripts {
  7604. +
  7605. +namespace {
  7606. +
  7607. +GURL GetEffectiveDocumentURL(
  7608. + blink::WebLocalFrame* frame,
  7609. + const GURL& document_url,
  7610. + MatchOriginAsFallbackBehavior match_origin_as_fallback,
  7611. + bool allow_inaccessible_parents) {
  7612. + auto should_consider_origin = [document_url, match_origin_as_fallback]() {
  7613. + switch (match_origin_as_fallback) {
  7614. + case MatchOriginAsFallbackBehavior::kNever:
  7615. + return false;
  7616. + case MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree:
  7617. + return document_url.SchemeIs(url::kAboutScheme);
  7618. + case MatchOriginAsFallbackBehavior::kAlways:
  7619. + // TODO(devlin): Add more schemes here - blob, filesystem, etc.
  7620. + return document_url.SchemeIs(url::kAboutScheme) ||
  7621. + document_url.SchemeIs(url::kDataScheme);
  7622. + }
  7623. +
  7624. + NOTREACHED();
  7625. + };
  7626. +
  7627. + // If we don't need to consider the origin, we're done.
  7628. + if (!should_consider_origin())
  7629. + return document_url;
  7630. +
  7631. + // Get the "security origin" for the frame. For about: frames, this is the
  7632. + // origin of that of the controlling frame - e.g., an about:blank frame on
  7633. + // https://example.com will have the security origin of https://example.com.
  7634. + // Other frames, like data: frames, will have an opaque origin. For these,
  7635. + // we can get the precursor origin.
  7636. + const blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin();
  7637. + const url::Origin frame_origin = web_frame_origin;
  7638. + const url::SchemeHostPort& tuple_or_precursor_tuple =
  7639. + frame_origin.GetTupleOrPrecursorTupleIfOpaque();
  7640. +
  7641. + // When there's no valid tuple (which can happen in the case of e.g. a
  7642. + // browser-initiated navigation to an opaque URL), there's no origin to
  7643. + // fallback to. Bail.
  7644. + if (!tuple_or_precursor_tuple.IsValid())
  7645. + return document_url;
  7646. +
  7647. + const url::Origin origin_or_precursor_origin =
  7648. + url::Origin::Create(tuple_or_precursor_tuple.GetURL());
  7649. +
  7650. + if (!allow_inaccessible_parents &&
  7651. + !web_frame_origin.CanAccess(
  7652. + blink::WebSecurityOrigin(origin_or_precursor_origin))) {
  7653. + // The frame can't access its precursor. Bail.
  7654. + return document_url;
  7655. + }
  7656. +
  7657. + // Looks like the initiator origin is an appropriate fallback!
  7658. +
  7659. + if (match_origin_as_fallback == MatchOriginAsFallbackBehavior::kAlways) {
  7660. + // The easy case! We use the origin directly. We're done.
  7661. + return origin_or_precursor_origin.GetURL();
  7662. + }
  7663. +
  7664. + DCHECK_EQ(MatchOriginAsFallbackBehavior::kMatchForAboutSchemeAndClimbTree,
  7665. + match_origin_as_fallback);
  7666. +
  7667. + // Unfortunately, in this case, we have to climb the frame tree. This is for
  7668. + // match patterns that are associated with paths as well, not just origins.
  7669. + // For instance, if an extension wants to run on google.com/maps/* with
  7670. + // match_about_blank true, then it should run on about:-scheme frames created
  7671. + // by google.com/maps, but not about:-scheme frames created by google.com
  7672. + // (which is what the precursor tuple origin would be).
  7673. +
  7674. + // Traverse the frame/window hierarchy to find the closest non-about:-page
  7675. + // with the same origin as the precursor and return its URL.
  7676. + // Note: This can return the incorrect result, e.g. if a parent frame
  7677. + // navigates a grandchild frame.
  7678. + blink::WebFrame* parent = frame;
  7679. + GURL parent_url;
  7680. + blink::WebDocument parent_document;
  7681. + base::flat_set<blink::WebFrame*> already_visited_frames;
  7682. + do {
  7683. + already_visited_frames.insert(parent);
  7684. + if (parent->Parent())
  7685. + parent = parent->Parent();
  7686. + else
  7687. + parent = parent->Opener();
  7688. +
  7689. + // Avoid an infinite loop - see https://crbug.com/568432 and
  7690. + // https://crbug.com/883526.
  7691. + if (base::Contains(already_visited_frames, parent))
  7692. + return document_url;
  7693. +
  7694. + parent_document = parent && parent->IsWebLocalFrame()
  7695. + ? parent->ToWebLocalFrame()->GetDocument()
  7696. + : blink::WebDocument();
  7697. +
  7698. + // We reached the end of the ancestral chain without finding a valid parent,
  7699. + // or found a remote web frame (in which case, it's a different origin).
  7700. + // Bail and use the original URL.
  7701. + if (parent_document.IsNull())
  7702. + return document_url;
  7703. +
  7704. + url::SchemeHostPort parent_tuple_or_precursor_tuple =
  7705. + url::Origin(parent->GetSecurityOrigin())
  7706. + .GetTupleOrPrecursorTupleIfOpaque();
  7707. + if (!parent_tuple_or_precursor_tuple.IsValid() ||
  7708. + parent_tuple_or_precursor_tuple != tuple_or_precursor_tuple) {
  7709. + // The parent has a different tuple origin than frame; this could happen
  7710. + // in edge cases where a parent navigates an iframe or popup of a child
  7711. + // frame at a different origin. [1] In this case, bail, since we can't
  7712. + // find a full URL (i.e., one including the path) with the same security
  7713. + // origin to use for the frame in question.
  7714. + // [1] Consider a frame tree like:
  7715. + // <html> <!--example.com-->
  7716. + // <iframe id="a" src="a.com">
  7717. + // <iframe id="b" src="b.com"></iframe>
  7718. + // </iframe>
  7719. + // </html>
  7720. + // Frame "a" is cross-origin from the top-level frame, and so the
  7721. + // example.com top-level frame can't directly access frame "b". However,
  7722. + // it can navigate it through
  7723. + // window.frames[0].frames[0].location.href = 'about:blank';
  7724. + // In that case, the precursor origin tuple origin of frame "b" would be
  7725. + // example.com, but the parent tuple origin is a.com.
  7726. + // Note that usually, this would have bailed earlier with a remote frame,
  7727. + // but it may not if we're at the process limit.
  7728. + return document_url;
  7729. + }
  7730. +
  7731. + parent_url = GURL(parent_document.Url());
  7732. + } while (parent_url.SchemeIs(url::kAboutScheme));
  7733. +
  7734. + DCHECK(!parent_url.is_empty());
  7735. + DCHECK(!parent_document.IsNull());
  7736. +
  7737. + // We should know that the frame can access the parent document (unless we
  7738. + // explicitly allow it not to), since it has the same tuple origin as the
  7739. + // frame, and we checked the frame access above.
  7740. + DCHECK(allow_inaccessible_parents ||
  7741. + web_frame_origin.CanAccess(parent_document.GetSecurityOrigin()));
  7742. + return parent_url;
  7743. +}
  7744. +
  7745. +using FrameToDocumentLoader =
  7746. + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>;
  7747. +
  7748. +FrameToDocumentLoader& FrameDocumentLoaderMap() {
  7749. + static base::NoDestructor<FrameToDocumentLoader> map;
  7750. + return *map;
  7751. +}
  7752. +
  7753. +blink::WebDocumentLoader* CurrentDocumentLoader(
  7754. + const blink::WebLocalFrame* frame) {
  7755. + auto& map = FrameDocumentLoaderMap();
  7756. + auto it = map.find(frame);
  7757. + return it == map.end() ? frame->GetDocumentLoader() : it->second;
  7758. +}
  7759. +
  7760. +} // namespace
  7761. +
  7762. +// static
  7763. +GURL ScriptContext::GetDocumentLoaderURLForFrame(
  7764. + const blink::WebLocalFrame* frame) {
  7765. + // Normally we would use frame->document().url() to determine the document's
  7766. + // URL, but to decide whether to inject a content script, we use the URL from
  7767. + // the data source. This "quirk" helps prevents content scripts from
  7768. + // inadvertently adding DOM elements to the compose iframe in Gmail because
  7769. + // the compose iframe's dataSource URL is about:blank, but the document URL
  7770. + // changes to match the parent document after Gmail document.writes into
  7771. + // it to create the editor.
  7772. + // http://code.google.com/p/chromium/issues/detail?id=86742
  7773. + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame);
  7774. + return document_loader ? GURL(document_loader->GetUrl()) : GURL();
  7775. +}
  7776. +
  7777. +// static
  7778. +GURL ScriptContext::GetEffectiveDocumentURLForInjection(
  7779. + blink::WebLocalFrame* frame,
  7780. + const GURL& document_url,
  7781. + MatchOriginAsFallbackBehavior match_origin_as_fallback) {
  7782. + // We explicitly allow inaccessible parents here. Extensions should still be
  7783. + // able to inject into a sandboxed iframe if it has access to the embedding
  7784. + // origin.
  7785. + constexpr bool allow_inaccessible_parents = true;
  7786. + return GetEffectiveDocumentURL(frame, document_url, match_origin_as_fallback,
  7787. + allow_inaccessible_parents);
  7788. +}
  7789. +
  7790. +} // namespace extensions
  7791. diff --git a/components/user_scripts/renderer/script_context.h b/components/user_scripts/renderer/script_context.h
  7792. new file mode 100755
  7793. --- /dev/null
  7794. +++ b/components/user_scripts/renderer/script_context.h
  7795. @@ -0,0 +1,70 @@
  7796. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7797. +// Use of this source code is governed by a BSD-style license that can be
  7798. +// found in the LICENSE file.
  7799. +
  7800. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7801. +#define USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7802. +
  7803. +#include <memory>
  7804. +#include <string>
  7805. +#include <utility>
  7806. +#include <vector>
  7807. +
  7808. +#include "base/callback.h"
  7809. +#include "base/compiler_specific.h"
  7810. +#include "base/macros.h"
  7811. +#include "base/threading/thread_checker.h"
  7812. +#include "base/unguessable_token.h"
  7813. +#include "../common/script_constants.h"
  7814. +#include "script_injection_callback.h"
  7815. +#include "url/gurl.h"
  7816. +#include "v8/include/v8.h"
  7817. +
  7818. +namespace blink {
  7819. +class WebDocumentLoader;
  7820. +class WebLocalFrame;
  7821. +}
  7822. +
  7823. +namespace content {
  7824. +class RenderFrame;
  7825. +}
  7826. +
  7827. +namespace user_scripts {
  7828. +
  7829. +// Extensions wrapper for a v8::Context.
  7830. +//
  7831. +// v8::Contexts can be constructed on any thread, and must only be accessed or
  7832. +// destroyed that thread.
  7833. +//
  7834. +// Note that ScriptContexts bound to worker threads will not have the full
  7835. +// functionality as those bound to the main RenderThread.
  7836. +class ScriptContext {
  7837. + public:
  7838. + // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  7839. + // vaguely ScriptContext related, there's enough here that they probably
  7840. + // warrant another class or utility file.
  7841. +
  7842. + // Utility to get the URL we will match against for a frame. If the frame has
  7843. + // committed, this is the commited URL. Otherwise it is the provisional URL.
  7844. + // The returned URL may be invalid.
  7845. + static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);
  7846. +
  7847. + // Used to determine the "effective" URL for extension script injection.
  7848. + // If |document_url| is an about: or data: URL, returns the URL of the first
  7849. + // frame without an about: or data: URL that matches the initiator origin.
  7850. + // This may not be the immediate parent. Returns |document_url| if it is not
  7851. + // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  7852. + // or if a suitable parent cannot be found.
  7853. + // Considers parent contexts that cannot be accessed (as is the case for
  7854. + // sandboxed frames).
  7855. + static GURL GetEffectiveDocumentURLForInjection(
  7856. + blink::WebLocalFrame* frame,
  7857. + const GURL& document_url,
  7858. + MatchOriginAsFallbackBehavior match_origin_as_fallback);
  7859. +
  7860. +// DISALLOW_COPY_AND_ASSIGN(ScriptContext);
  7861. +};
  7862. +
  7863. +} // namespace extensions
  7864. +
  7865. +#endif // USERSCRIPTS_RENDERER_SCRIPT_CONTEXT_H_
  7866. diff --git a/components/user_scripts/renderer/script_injection.cc b/components/user_scripts/renderer/script_injection.cc
  7867. new file mode 100755
  7868. --- /dev/null
  7869. +++ b/components/user_scripts/renderer/script_injection.cc
  7870. @@ -0,0 +1,342 @@
  7871. +// Copyright 2014 The Chromium Authors. All rights reserved.
  7872. +// Use of this source code is governed by a BSD-style license that can be
  7873. +// found in the LICENSE file.
  7874. +
  7875. +#include "script_injection.h"
  7876. +
  7877. +#include <map>
  7878. +#include <utility>
  7879. +
  7880. +#include "base/bind.h"
  7881. +#include "base/feature_list.h"
  7882. +#include "base/lazy_instance.h"
  7883. +#include "base/macros.h"
  7884. +#include "base/metrics/histogram_macros.h"
  7885. +#include "base/timer/elapsed_timer.h"
  7886. +#include "base/values.h"
  7887. +#include "base/logging.h"
  7888. +#include "content/public/renderer/render_frame.h"
  7889. +#include "content/public/renderer/render_frame_observer.h"
  7890. +#include "content/public/renderer/v8_value_converter.h"
  7891. +#include "../common/host_id.h"
  7892. +#include "script_injection_callback.h"
  7893. +#include "scripts_run_info.h"
  7894. +#include "third_party/blink/public/platform/web_isolated_world_info.h"
  7895. +#include "third_party/blink/public/platform/web_security_origin.h"
  7896. +#include "third_party/blink/public/platform/web_string.h"
  7897. +#include "third_party/blink/public/web/web_document.h"
  7898. +#include "third_party/blink/public/web/web_local_frame.h"
  7899. +#include "third_party/blink/public/web/web_script_source.h"
  7900. +#include "url/gurl.h"
  7901. +
  7902. +namespace user_scripts {
  7903. +
  7904. +namespace {
  7905. +
  7906. +using IsolatedWorldMap = std::map<std::string, int>;
  7907. +base::LazyInstance<IsolatedWorldMap>::DestructorAtExit g_isolated_worlds =
  7908. + LAZY_INSTANCE_INITIALIZER;
  7909. +
  7910. +const int64_t kInvalidRequestId = -1;
  7911. +
  7912. +// Gets the isolated world ID to use for the given |injection_host|. If no
  7913. +// isolated world has been created for that |injection_host| one will be created
  7914. +// and initialized.
  7915. +int GetIsolatedWorldIdForInstance(const InjectionHost* injection_host) {
  7916. + static int g_next_isolated_world_id = 1; // Embedder isolated worlds can use IDs in [1, 1<<29).
  7917. +
  7918. + IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  7919. +
  7920. + int id = 0;
  7921. + const std::string& key = injection_host->id().id();
  7922. + auto iter = isolated_worlds.find(key);
  7923. + if (iter != isolated_worlds.end()) {
  7924. + id = iter->second;
  7925. + } else {
  7926. + id = g_next_isolated_world_id++;
  7927. + // This map will tend to pile up over time, but realistically, you're never
  7928. + // going to have enough injection hosts for it to matter.
  7929. + isolated_worlds[key] = id;
  7930. + }
  7931. +
  7932. + blink::WebIsolatedWorldInfo info;
  7933. + info.security_origin =
  7934. + blink::WebSecurityOrigin::Create(injection_host->url());
  7935. + info.human_readable_name = blink::WebString::FromUTF8(injection_host->name());
  7936. + info.stable_id = blink::WebString::FromUTF8(key);
  7937. +
  7938. + const std::string* csp = injection_host->GetContentSecurityPolicy();
  7939. + if (csp)
  7940. + info.content_security_policy = blink::WebString::FromUTF8(*csp);
  7941. +
  7942. + // Even though there may be an existing world for this |injection_host|'s key,
  7943. + // the properties may have changed (e.g. due to an extension update).
  7944. + // Overwrite any existing entries.
  7945. + blink::SetIsolatedWorldInfo(id, info);
  7946. +
  7947. + return id;
  7948. +}
  7949. +
  7950. +// This class manages its own lifetime.
  7951. +class TimedScriptInjectionCallback : public ScriptInjectionCallback {
  7952. + public:
  7953. + TimedScriptInjectionCallback(base::WeakPtr<ScriptInjection> injection)
  7954. + : ScriptInjectionCallback(
  7955. + base::Bind(&TimedScriptInjectionCallback::OnCompleted,
  7956. + base::Unretained(this))),
  7957. + injection_(injection) {}
  7958. + ~TimedScriptInjectionCallback() override {}
  7959. +
  7960. + void OnCompleted(const std::vector<v8::Local<v8::Value>>& result) {
  7961. + if (injection_) {
  7962. + base::TimeTicks timestamp(base::TimeTicks::Now());
  7963. + base::Optional<base::TimeDelta> elapsed;
  7964. + // If the script will never execute (such as if the context is destroyed),
  7965. + // willExecute() will not be called, but OnCompleted() will. Only log a
  7966. + // time for execution if the script, in fact, executed.
  7967. + if (!start_time_.is_null())
  7968. + elapsed = timestamp - start_time_;
  7969. + injection_->OnJsInjectionCompleted(result, elapsed);
  7970. + }
  7971. + }
  7972. +
  7973. + void WillExecute() override {
  7974. + start_time_ = base::TimeTicks::Now();
  7975. + }
  7976. +
  7977. + private:
  7978. + base::WeakPtr<ScriptInjection> injection_;
  7979. + base::TimeTicks start_time_;
  7980. +};
  7981. +
  7982. +} // namespace
  7983. +
  7984. +// Watches for the deletion of a RenderFrame, after which is_valid will return
  7985. +// false.
  7986. +class ScriptInjection::FrameWatcher : public content::RenderFrameObserver {
  7987. + public:
  7988. + FrameWatcher(content::RenderFrame* render_frame,
  7989. + ScriptInjection* injection)
  7990. + : content::RenderFrameObserver(render_frame),
  7991. + injection_(injection) {}
  7992. + ~FrameWatcher() override {}
  7993. +
  7994. + private:
  7995. + void WillDetach() override { injection_->invalidate_render_frame(); }
  7996. + void OnDestruct() override { injection_->invalidate_render_frame(); }
  7997. +
  7998. + ScriptInjection* injection_;
  7999. +
  8000. + DISALLOW_COPY_AND_ASSIGN(FrameWatcher);
  8001. +};
  8002. +
  8003. +// static
  8004. +std::string ScriptInjection::GetHostIdForIsolatedWorld(int isolated_world_id) {
  8005. + const IsolatedWorldMap& isolated_worlds = g_isolated_worlds.Get();
  8006. +
  8007. + for (const auto& iter : isolated_worlds) {
  8008. + if (iter.second == isolated_world_id)
  8009. + return iter.first;
  8010. + }
  8011. + return std::string();
  8012. +}
  8013. +
  8014. +// static
  8015. +void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
  8016. + g_isolated_worlds.Get().erase(host_id);
  8017. +}
  8018. +
  8019. +ScriptInjection::ScriptInjection(
  8020. + std::unique_ptr<ScriptInjector> injector,
  8021. + content::RenderFrame* render_frame,
  8022. + std::unique_ptr<const InjectionHost> injection_host,
  8023. + UserScript::RunLocation run_location,
  8024. + bool log_activity)
  8025. + : injector_(std::move(injector)),
  8026. + render_frame_(render_frame),
  8027. + injection_host_(std::move(injection_host)),
  8028. + run_location_(run_location),
  8029. + request_id_(kInvalidRequestId),
  8030. + complete_(false),
  8031. + did_inject_js_(false),
  8032. + log_activity_(log_activity),
  8033. + frame_watcher_(new FrameWatcher(render_frame, this)) {
  8034. + CHECK(injection_host_.get());
  8035. +}
  8036. +
  8037. +ScriptInjection::~ScriptInjection() {
  8038. + if (!complete_)
  8039. + NotifyWillNotInject(ScriptInjector::WONT_INJECT);
  8040. +}
  8041. +
  8042. +ScriptInjection::InjectionResult ScriptInjection::TryToInject(
  8043. + UserScript::RunLocation current_location,
  8044. + ScriptsRunInfo* scripts_run_info,
  8045. + CompletionCallback async_completion_callback) {
  8046. + if (current_location < run_location_)
  8047. + return INJECTION_WAITING; // Wait for the right location.
  8048. +
  8049. + if (request_id_ != kInvalidRequestId) {
  8050. + // We're waiting for permission right now, try again later.
  8051. + return INJECTION_WAITING;
  8052. + }
  8053. +
  8054. + if (!injection_host_) {
  8055. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8056. + return INJECTION_FINISHED; // We're done.
  8057. + }
  8058. +
  8059. + InjectionResult result = Inject(scripts_run_info);
  8060. + // If the injection is blocked, we need to set the manager so we can
  8061. + // notify it upon completion.
  8062. + if (result == INJECTION_BLOCKED)
  8063. + async_completion_callback_ = std::move(async_completion_callback);
  8064. + return result;
  8065. +}
  8066. +
  8067. +ScriptInjection::InjectionResult ScriptInjection::OnPermissionGranted(
  8068. + ScriptsRunInfo* scripts_run_info) {
  8069. + if (!injection_host_) {
  8070. + NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
  8071. + return INJECTION_FINISHED;
  8072. + }
  8073. +
  8074. + return Inject(scripts_run_info);
  8075. +}
  8076. +
  8077. +void ScriptInjection::OnHostRemoved() {
  8078. + injection_host_.reset(nullptr);
  8079. +}
  8080. +
  8081. +void ScriptInjection::NotifyWillNotInject(
  8082. + ScriptInjector::InjectFailureReason reason) {
  8083. + complete_ = true;
  8084. + injector_->OnWillNotInject(reason, render_frame_);
  8085. +}
  8086. +
  8087. +ScriptInjection::InjectionResult ScriptInjection::Inject(
  8088. + ScriptsRunInfo* scripts_run_info) {
  8089. + DCHECK(injection_host_);
  8090. + //DCHECK(scripts_run_info);
  8091. + DCHECK(!complete_);
  8092. + bool should_inject_js = injector_->ShouldInjectJs(
  8093. + run_location_, scripts_run_info->executing_scripts[host_id().id()]);
  8094. + bool should_inject_css = injector_->ShouldInjectCss(
  8095. + run_location_, scripts_run_info->injected_stylesheets[host_id().id()]);
  8096. +
  8097. + // This can happen if the extension specified a script to
  8098. + // be run in multiple rules, and the script has already run.
  8099. + // See crbug.com/631247.
  8100. + if (!should_inject_js && !should_inject_css) {
  8101. + return INJECTION_FINISHED;
  8102. + }
  8103. +
  8104. + if (should_inject_js)
  8105. + InjectJs(&(scripts_run_info->executing_scripts[host_id().id()]),
  8106. + &(scripts_run_info->num_js));
  8107. + if (should_inject_css)
  8108. + InjectCss(&(scripts_run_info->injected_stylesheets[host_id().id()]),
  8109. + &(scripts_run_info->num_css));
  8110. +
  8111. + complete_ = did_inject_js_ || !should_inject_js;
  8112. +
  8113. + if (complete_) {
  8114. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8115. + render_frame_);
  8116. + } else {
  8117. + ++scripts_run_info->num_blocking_js;
  8118. + }
  8119. +
  8120. + return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
  8121. +}
  8122. +
  8123. +void ScriptInjection::InjectJs(std::set<std::string>* executing_scripts,
  8124. + size_t* num_injected_js_scripts) {
  8125. + DCHECK(!did_inject_js_);
  8126. + std::vector<blink::WebScriptSource> sources = injector_->GetJsSources(
  8127. + run_location_, executing_scripts, num_injected_js_scripts);
  8128. + DCHECK(!sources.empty());
  8129. + int world_id = GetIsolatedWorldIdForInstance(injection_host_.get());
  8130. + bool is_user_gesture = injector_->IsUserGesture();
  8131. +
  8132. + std::unique_ptr<blink::WebScriptExecutionCallback> callback(
  8133. + new TimedScriptInjectionCallback(weak_ptr_factory_.GetWeakPtr()));
  8134. +
  8135. + base::ElapsedTimer exec_timer;
  8136. +
  8137. + // For content scripts executing during page load, we run them asynchronously
  8138. + // in order to reduce UI jank experienced by the user. (We don't do this for
  8139. + // DOCUMENT_START scripts, because there's no UI to jank until after those
  8140. + // run, so we run them as soon as we can.)
  8141. + // Note: We could potentially also run deferred and browser-driven scripts
  8142. + // asynchronously; however, these are rare enough that there probably isn't
  8143. + // UI jank. If this changes, we can update this.
  8144. + bool should_execute_asynchronously =
  8145. + injector_->script_type() == UserScript::CONTENT_SCRIPT &&
  8146. + (run_location_ == UserScript::DOCUMENT_END ||
  8147. + run_location_ == UserScript::DOCUMENT_IDLE);
  8148. + blink::WebLocalFrame::ScriptExecutionType execution_option =
  8149. + should_execute_asynchronously
  8150. + ? blink::WebLocalFrame::kAsynchronousBlockingOnload
  8151. + : blink::WebLocalFrame::kSynchronous;
  8152. +
  8153. + render_frame_->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
  8154. + world_id, &sources.front(), sources.size(), is_user_gesture,
  8155. + execution_option, callback.release());
  8156. +}
  8157. +
  8158. +void ScriptInjection::OnJsInjectionCompleted(
  8159. + const std::vector<v8::Local<v8::Value>>& results,
  8160. + base::Optional<base::TimeDelta> elapsed) {
  8161. + DCHECK(!did_inject_js_);
  8162. +
  8163. + bool expects_results = injector_->ExpectsResults();
  8164. + if (expects_results) {
  8165. + if (!results.empty() && !results[0].IsEmpty()) {
  8166. + // Right now, we only support returning single results (per frame).
  8167. + // It's safe to always use the main world context when converting
  8168. + // here. V8ValueConverterImpl shouldn't actually care about the
  8169. + // context scope, and it switches to v8::Object's creation context
  8170. + // when encountered.
  8171. + v8::Local<v8::Context> context =
  8172. + render_frame_->GetWebFrame()->MainWorldScriptContext();
  8173. + execution_result_ =
  8174. + content::V8ValueConverter::Create()->FromV8Value(results[0], context);
  8175. + }
  8176. + if (!execution_result_.get())
  8177. + execution_result_ = std::make_unique<base::Value>();
  8178. + }
  8179. + did_inject_js_ = true;
  8180. +
  8181. + // If |async_completion_callback_| is set, it means the script finished
  8182. + // asynchronously, and we should run it.
  8183. + if (!async_completion_callback_.is_null()) {
  8184. + complete_ = true;
  8185. + injector_->OnInjectionComplete(std::move(execution_result_), run_location_,
  8186. + render_frame_);
  8187. + // Warning: this object can be destroyed after this line!
  8188. + std::move(async_completion_callback_).Run(this);
  8189. + }
  8190. +}
  8191. +
  8192. +void ScriptInjection::InjectCss(std::set<std::string>* injected_stylesheets,
  8193. + size_t* num_injected_stylesheets) {
  8194. + std::vector<blink::WebString> css_sources = injector_->GetCssSources(
  8195. + run_location_, injected_stylesheets, num_injected_stylesheets);
  8196. + blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
  8197. + // Default CSS origin is "author", but can be overridden to "user" by scripts.
  8198. + base::Optional<CSSOrigin> css_origin = injector_->GetCssOrigin();
  8199. + blink::WebDocument::CSSOrigin blink_css_origin =
  8200. + css_origin && *css_origin == CSS_ORIGIN_USER
  8201. + ? blink::WebDocument::kUserOrigin
  8202. + : blink::WebDocument::kAuthorOrigin;
  8203. + blink::WebStyleSheetKey style_sheet_key;
  8204. + if (const base::Optional<std::string>& injection_key =
  8205. + injector_->GetInjectionKey())
  8206. + style_sheet_key = blink::WebString::FromASCII(*injection_key);
  8207. + for (const blink::WebString& css : css_sources)
  8208. + web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key,
  8209. + blink_css_origin);
  8210. +}
  8211. +
  8212. +} // namespace extensions
  8213. diff --git a/components/user_scripts/renderer/script_injection.h b/components/user_scripts/renderer/script_injection.h
  8214. new file mode 100755
  8215. --- /dev/null
  8216. +++ b/components/user_scripts/renderer/script_injection.h
  8217. @@ -0,0 +1,156 @@
  8218. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8219. +// Use of this source code is governed by a BSD-style license that can be
  8220. +// found in the LICENSE file.
  8221. +
  8222. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8223. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8224. +
  8225. +#include <stdint.h>
  8226. +
  8227. +#include <memory>
  8228. +#include <vector>
  8229. +
  8230. +#include "base/callback.h"
  8231. +#include "base/macros.h"
  8232. +#include "base/memory/weak_ptr.h"
  8233. +#include "base/optional.h"
  8234. +#include "../common/user_script.h"
  8235. +#include "injection_host.h"
  8236. +#include "script_injector.h"
  8237. +
  8238. +struct HostID;
  8239. +
  8240. +namespace content {
  8241. +class RenderFrame;
  8242. +}
  8243. +
  8244. +namespace v8 {
  8245. +class Value;
  8246. +template <class T> class Local;
  8247. +}
  8248. +
  8249. +namespace user_scripts {
  8250. +struct ScriptsRunInfo;
  8251. +
  8252. +// A script wrapper which is aware of whether or not it is allowed to execute,
  8253. +// and contains the implementation to do so.
  8254. +class ScriptInjection {
  8255. + public:
  8256. + enum InjectionResult {
  8257. + INJECTION_FINISHED,
  8258. + INJECTION_BLOCKED,
  8259. + INJECTION_WAITING
  8260. + };
  8261. +
  8262. + using CompletionCallback = base::OnceCallback<void(ScriptInjection*)>;
  8263. +
  8264. + // Return the id of the injection host associated with the given world.
  8265. + static std::string GetHostIdForIsolatedWorld(int world_id);
  8266. +
  8267. + // Remove the isolated world associated with the given injection host.
  8268. + static void RemoveIsolatedWorld(const std::string& host_id);
  8269. +
  8270. + ScriptInjection(std::unique_ptr<ScriptInjector> injector,
  8271. + content::RenderFrame* render_frame,
  8272. + std::unique_ptr<const InjectionHost> injection_host,
  8273. + UserScript::RunLocation run_location,
  8274. + bool log_activity);
  8275. + ~ScriptInjection();
  8276. +
  8277. + // Try to inject the script at the |current_location|. This returns
  8278. + // INJECTION_FINISHED if injection has injected or will never inject, returns
  8279. + // INJECTION_BLOCKED if injection is running asynchronously and has not
  8280. + // finished yet, returns INJECTION_WAITING if injections is delayed (either
  8281. + // for permission purposes or because |current_location| is not the designated
  8282. + // |run_location_|).
  8283. + // If INJECTION_BLOCKED is returned, |async_completion_callback| will be
  8284. + // called upon completion.
  8285. + InjectionResult TryToInject(
  8286. + UserScript::RunLocation current_location,
  8287. + ScriptsRunInfo* scripts_run_info,
  8288. + CompletionCallback async_completion_callback);
  8289. +
  8290. + // Called when permission for the given injection has been granted.
  8291. + // Returns INJECTION_FINISHED if injection has injected or will never inject,
  8292. + // returns INJECTION_BLOCKED if injection is ran asynchronously.
  8293. + InjectionResult OnPermissionGranted(ScriptsRunInfo* scripts_run_info);
  8294. +
  8295. + // Resets the pointer of the injection host when the host is gone.
  8296. + void OnHostRemoved();
  8297. +
  8298. + void invalidate_render_frame() { render_frame_ = nullptr; }
  8299. +
  8300. + // Accessors.
  8301. + content::RenderFrame* render_frame() const { return render_frame_; }
  8302. + const HostID& host_id() const { return injection_host_->id(); }
  8303. + int64_t request_id() const { return request_id_; }
  8304. +
  8305. + // Called when JS injection for the given frame has been completed or
  8306. + // cancelled.
  8307. + void OnJsInjectionCompleted(const std::vector<v8::Local<v8::Value>>& results,
  8308. + base::Optional<base::TimeDelta> elapsed);
  8309. +
  8310. + private:
  8311. + class FrameWatcher;
  8312. +
  8313. + // Sends a message to the browser to request permission to inject.
  8314. + void RequestPermissionFromBrowser();
  8315. +
  8316. + // Injects the script. Returns INJECTION_FINISHED if injection has finished,
  8317. + // otherwise INJECTION_BLOCKED.
  8318. + InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
  8319. +
  8320. + // Inject any JS scripts into the frame for the injection.
  8321. + void InjectJs(std::set<std::string>* executing_scripts,
  8322. + size_t* num_injected_js_scripts);
  8323. +
  8324. + // Inject any CSS source into the frame for the injection.
  8325. + void InjectCss(std::set<std::string>* injected_stylesheets,
  8326. + size_t* num_injected_stylesheets);
  8327. +
  8328. + // Notify that we will not inject, and mark it as acknowledged.
  8329. + void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
  8330. +
  8331. + // The injector for this injection.
  8332. + std::unique_ptr<ScriptInjector> injector_;
  8333. +
  8334. + // The RenderFrame into which this should inject the script.
  8335. + content::RenderFrame* render_frame_;
  8336. +
  8337. + // The associated injection host.
  8338. + std::unique_ptr<const InjectionHost> injection_host_;
  8339. +
  8340. + // The location in the document load at which we inject the script.
  8341. + UserScript::RunLocation run_location_;
  8342. +
  8343. + // This injection's request id. This will be -1 unless the injection is
  8344. + // currently waiting on permission.
  8345. + int64_t request_id_;
  8346. +
  8347. + // Whether or not the injection is complete, either via injecting the script
  8348. + // or because it will never complete.
  8349. + bool complete_;
  8350. +
  8351. + // Whether or not the injection successfully injected JS.
  8352. + bool did_inject_js_;
  8353. +
  8354. + // Whether or not we should log dom activity for this injection.
  8355. + bool log_activity_;
  8356. +
  8357. + // Results storage.
  8358. + std::unique_ptr<base::Value> execution_result_;
  8359. +
  8360. + // The callback to run upon completing asynchronously.
  8361. + CompletionCallback async_completion_callback_;
  8362. +
  8363. + // A helper class to hold the render frame and watch for its deletion.
  8364. + std::unique_ptr<FrameWatcher> frame_watcher_;
  8365. +
  8366. + base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_{this};
  8367. +
  8368. + DISALLOW_COPY_AND_ASSIGN(ScriptInjection);
  8369. +};
  8370. +
  8371. +} // namespace extensions
  8372. +
  8373. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_H_
  8374. diff --git a/components/user_scripts/renderer/script_injection_callback.cc b/components/user_scripts/renderer/script_injection_callback.cc
  8375. new file mode 100755
  8376. --- /dev/null
  8377. +++ b/components/user_scripts/renderer/script_injection_callback.cc
  8378. @@ -0,0 +1,26 @@
  8379. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8380. +// Use of this source code is governed by a BSD-style license that can be
  8381. +// found in the LICENSE file.
  8382. +
  8383. +#include "script_injection_callback.h"
  8384. +
  8385. +#include "third_party/blink/public/platform/web_vector.h"
  8386. +
  8387. +namespace user_scripts {
  8388. +
  8389. +ScriptInjectionCallback::ScriptInjectionCallback(
  8390. + const CompleteCallback& injection_completed_callback)
  8391. + : injection_completed_callback_(injection_completed_callback) {
  8392. +}
  8393. +
  8394. +ScriptInjectionCallback::~ScriptInjectionCallback() {
  8395. +}
  8396. +
  8397. +void ScriptInjectionCallback::Completed(
  8398. + const blink::WebVector<v8::Local<v8::Value>>& result) {
  8399. + std::vector<v8::Local<v8::Value>> stl_result(result.begin(), result.end());
  8400. + injection_completed_callback_.Run(stl_result);
  8401. + delete this;
  8402. +}
  8403. +
  8404. +} // namespace extensions
  8405. diff --git a/components/user_scripts/renderer/script_injection_callback.h b/components/user_scripts/renderer/script_injection_callback.h
  8406. new file mode 100755
  8407. --- /dev/null
  8408. +++ b/components/user_scripts/renderer/script_injection_callback.h
  8409. @@ -0,0 +1,38 @@
  8410. +// Copyright 2015 The Chromium Authors. All rights reserved.
  8411. +// Use of this source code is governed by a BSD-style license that can be
  8412. +// found in the LICENSE file.
  8413. +
  8414. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8415. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8416. +
  8417. +#include <vector>
  8418. +
  8419. +#include "base/callback.h"
  8420. +#include "base/macros.h"
  8421. +#include "third_party/blink/public/web/web_script_execution_callback.h"
  8422. +#include "v8/include/v8.h"
  8423. +
  8424. +namespace user_scripts {
  8425. +
  8426. +// A wrapper around a callback to notify a script injection when injection
  8427. +// completes.
  8428. +// This class manages its own lifetime.
  8429. +class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  8430. + public:
  8431. + using CompleteCallback =
  8432. + base::Callback<void(const std::vector<v8::Local<v8::Value>>& result)>;
  8433. +
  8434. + ScriptInjectionCallback(const CompleteCallback& injection_completed_callback);
  8435. + ~ScriptInjectionCallback() override;
  8436. +
  8437. + void Completed(const blink::WebVector<v8::Local<v8::Value>>& result) override;
  8438. +
  8439. + private:
  8440. + CompleteCallback injection_completed_callback_;
  8441. +
  8442. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionCallback);
  8443. +};
  8444. +
  8445. +} // namespace extensions
  8446. +
  8447. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
  8448. diff --git a/components/user_scripts/renderer/script_injection_manager.cc b/components/user_scripts/renderer/script_injection_manager.cc
  8449. new file mode 100755
  8450. --- /dev/null
  8451. +++ b/components/user_scripts/renderer/script_injection_manager.cc
  8452. @@ -0,0 +1,417 @@
  8453. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8454. +// Use of this source code is governed by a BSD-style license that can be
  8455. +// found in the LICENSE file.
  8456. +
  8457. +#include "script_injection_manager.h"
  8458. +
  8459. +#include <memory>
  8460. +#include <utility>
  8461. +
  8462. +#include "base/auto_reset.h"
  8463. +#include "base/bind.h"
  8464. +#include "base/feature_list.h"
  8465. +#include "base/memory/weak_ptr.h"
  8466. +#include "base/threading/thread_task_runner_handle.h"
  8467. +#include "base/values.h"
  8468. +#include "base/logging.h"
  8469. +#include "content/public/renderer/render_frame.h"
  8470. +#include "content/public/renderer/render_frame_observer.h"
  8471. +#include "content/public/renderer/render_thread.h"
  8472. +#include "extension_frame_helper.h"
  8473. +#include "../common/host_id.h"
  8474. +#include "script_injection.h"
  8475. +#include "scripts_run_info.h"
  8476. +#include "web_ui_injection_host.h"
  8477. +#include "ipc/ipc_message_macros.h"
  8478. +#include "third_party/blink/public/platform/web_url_error.h"
  8479. +#include "third_party/blink/public/web/web_document.h"
  8480. +#include "third_party/blink/public/web/web_frame.h"
  8481. +#include "third_party/blink/public/web/web_local_frame.h"
  8482. +#include "third_party/blink/public/web/web_view.h"
  8483. +#include "url/gurl.h"
  8484. +#include "../common/user_scripts_features.h"
  8485. +
  8486. +namespace user_scripts {
  8487. +
  8488. +namespace {
  8489. +
  8490. +// The length of time to wait after the DOM is complete to try and run user
  8491. +// scripts.
  8492. +const int kScriptIdleTimeoutInMs = 200;
  8493. +
  8494. +// Returns the RunLocation that follows |run_location|.
  8495. +UserScript::RunLocation NextRunLocation(UserScript::RunLocation run_location) {
  8496. + switch (run_location) {
  8497. + case UserScript::DOCUMENT_START:
  8498. + return UserScript::DOCUMENT_END;
  8499. + case UserScript::DOCUMENT_END:
  8500. + return UserScript::DOCUMENT_IDLE;
  8501. + case UserScript::DOCUMENT_IDLE:
  8502. + return UserScript::RUN_LOCATION_LAST;
  8503. + case UserScript::UNDEFINED:
  8504. + case UserScript::RUN_DEFERRED:
  8505. + case UserScript::BROWSER_DRIVEN:
  8506. + case UserScript::RUN_LOCATION_LAST:
  8507. + break;
  8508. + }
  8509. + NOTREACHED();
  8510. + return UserScript::RUN_LOCATION_LAST;
  8511. +}
  8512. +
  8513. +} // namespace
  8514. +
  8515. +class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
  8516. + public:
  8517. + RFOHelper(content::RenderFrame* render_frame,
  8518. + ScriptInjectionManager* manager);
  8519. + ~RFOHelper() override;
  8520. +
  8521. + // commit @9f2aac4
  8522. + void Initialize();
  8523. +
  8524. + private:
  8525. + // RenderFrameObserver implementation.
  8526. + void DidCreateNewDocument() override;
  8527. + void DidCreateDocumentElement() override;
  8528. + void DidFailProvisionalLoad() override;
  8529. + void DidFinishDocumentLoad() override;
  8530. + void WillDetach() override;
  8531. + void OnDestruct() override;
  8532. + void OnStop() override;
  8533. +
  8534. + // Tells the ScriptInjectionManager to run tasks associated with
  8535. + // document_idle.
  8536. + void RunIdle();
  8537. +
  8538. + void StartInjectScripts(UserScript::RunLocation run_location);
  8539. +
  8540. + // Indicate that the frame is no longer valid because it is starting
  8541. + // a new load or closing.
  8542. + void InvalidateAndResetFrame(bool force_reset);
  8543. +
  8544. + // The owning ScriptInjectionManager.
  8545. + ScriptInjectionManager* manager_;
  8546. +
  8547. + bool should_run_idle_ = true; // commit @9f2aac4
  8548. +
  8549. + base::WeakPtrFactory<RFOHelper> weak_factory_{this};
  8550. +};
  8551. +
  8552. +ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
  8553. + ScriptInjectionManager* manager)
  8554. + : content::RenderFrameObserver(render_frame),
  8555. + manager_(manager),
  8556. + should_run_idle_(true) {}
  8557. +
  8558. +ScriptInjectionManager::RFOHelper::~RFOHelper() {
  8559. +}
  8560. +
  8561. +
  8562. +void ScriptInjectionManager::RFOHelper::Initialize() {
  8563. + // Set up for the initial empty document, for which the Document created
  8564. + // events do not happen as it's already present.
  8565. + DidCreateNewDocument();
  8566. + // The initial empty document for a main frame may have scripts attached to it
  8567. + // but we do not want to invalidate the frame and lose them when the next
  8568. + // document loads. For example the IncognitoApiTest.IncognitoSplitMode test
  8569. + // does `chrome.tabs.create()` with a script to be run, which is added to the
  8570. + // frame before it navigates, so it needs to be preserved. However scripts in
  8571. + // child frames are expected to be run inside the initial empty document. For
  8572. + // example the ExecuteScriptApiTest.FrameWithHttp204 test creates a child
  8573. + // frame at about:blank and expects to run injected scripts inside it.
  8574. + // This is all quite inconsistent however tests both depend on us queuing and
  8575. + // not queueing the DOCUMENT_START events in the initial empty document.
  8576. + if (!render_frame()->IsMainFrame()) {
  8577. + DidCreateDocumentElement();
  8578. + }
  8579. +}
  8580. +
  8581. +void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() {
  8582. + // A new document is going to be shown, so invalidate the old document state.
  8583. + // Don't force-reset the frame, because it is possible that a script injection
  8584. + // was scheduled before the page was loaded, e.g. by navigating to a
  8585. + // javascript: URL before the page has loaded.
  8586. + constexpr bool kForceReset = false;
  8587. + InvalidateAndResetFrame(kForceReset);
  8588. +}
  8589. +
  8590. +void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
  8591. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8592. + LOG(INFO) << "UserScripts: DidCreateDocumentElement -> DOCUMENT_START";
  8593. +
  8594. + ExtensionFrameHelper::Get(render_frame())
  8595. + ->ScheduleAtDocumentStart(
  8596. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8597. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START));
  8598. +}
  8599. +
  8600. +void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad() {
  8601. + auto it = manager_->frame_statuses_.find(render_frame());
  8602. + if (it != manager_->frame_statuses_.end() &&
  8603. + it->second == UserScript::DOCUMENT_START) {
  8604. + // Since the provisional load failed, the frame stays at its previous loaded
  8605. + // state and origin (or the parent's origin for new/about:blank frames).
  8606. + // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is
  8607. + // done loading, and avoid any deadlock in the system.
  8608. + //
  8609. + // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the
  8610. + // injections closely follow the DOMContentLoaded (and onload) events, which
  8611. + // are not triggered after a failed provisional load.
  8612. + // This assumption is verified in the checkDOMContentLoadedEvent subtest of
  8613. + // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests).
  8614. + constexpr bool kForceReset = true;
  8615. + InvalidateAndResetFrame(kForceReset);
  8616. + should_run_idle_ = false;
  8617. + manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE;
  8618. + }
  8619. +}
  8620. +
  8621. +void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() {
  8622. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8623. + LOG(INFO) << "UserScripts: DidFinishDocumentLoad -> DOCUMENT_END";
  8624. +
  8625. + DCHECK(content::RenderThread::Get());
  8626. + ExtensionFrameHelper::Get(render_frame())
  8627. + ->ScheduleAtDocumentEnd(
  8628. + base::BindOnce(&ScriptInjectionManager::RFOHelper::StartInjectScripts,
  8629. + weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END));
  8630. +
  8631. + // We try to run idle in two places: a delayed task here and in response to
  8632. + // ContentRendererClient::RunScriptsAtDocumentIdle(). DidFinishDocumentLoad()
  8633. + // corresponds to completing the document's load, whereas
  8634. + // RunScriptsAtDocumentIdle() corresponds to completing the document and all
  8635. + // subresources' load (but before the window.onload event). We don't want to
  8636. + // hold up script injection for a particularly slow subresource, so we set a
  8637. + // delayed task from here - but if we finish everything before that point
  8638. + // (i.e., RunScriptsAtDocumentIdle() is triggered), then there's no reason to
  8639. + // keep waiting.
  8640. + render_frame()
  8641. + ->GetTaskRunner(blink::TaskType::kInternalDefault)
  8642. + ->PostDelayedTask(
  8643. + FROM_HERE,
  8644. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8645. + weak_factory_.GetWeakPtr()),
  8646. + base::TimeDelta::FromMilliseconds(kScriptIdleTimeoutInMs));
  8647. +
  8648. + ExtensionFrameHelper::Get(render_frame())
  8649. + ->ScheduleAtDocumentIdle(
  8650. + base::BindOnce(&ScriptInjectionManager::RFOHelper::RunIdle,
  8651. + weak_factory_.GetWeakPtr()));
  8652. +}
  8653. +
  8654. +void ScriptInjectionManager::RFOHelper::WillDetach() {
  8655. + // The frame is closing - invalidate.
  8656. + constexpr bool kForceReset = true;
  8657. + InvalidateAndResetFrame(kForceReset);
  8658. +}
  8659. +
  8660. +void ScriptInjectionManager::RFOHelper::OnDestruct() {
  8661. + manager_->RemoveObserver(this);
  8662. +}
  8663. +
  8664. +void ScriptInjectionManager::RFOHelper::OnStop() {
  8665. + // If the navigation request fails (e.g. 204/205/downloads), notify the
  8666. + // extension to avoid keeping the frame in a START state indefinitely which
  8667. + // leads to deadlocks.
  8668. + DidFailProvisionalLoad();
  8669. +}
  8670. +
  8671. +void ScriptInjectionManager::RFOHelper::RunIdle() {
  8672. + // Only notify the manager if the frame hasn't already had idle run since the
  8673. + // task to RunIdle() was posted.
  8674. + if (should_run_idle_) {
  8675. + should_run_idle_ = false;
  8676. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  8677. + LOG(INFO) << "UserScripts: RunIdle -> DOCUMENT_IDLE";
  8678. + manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
  8679. + }
  8680. +}
  8681. +
  8682. +void ScriptInjectionManager::RFOHelper::StartInjectScripts(
  8683. + UserScript::RunLocation run_location) {
  8684. + manager_->StartInjectScripts(render_frame(), run_location);
  8685. +}
  8686. +
  8687. +void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame(
  8688. + bool force_reset) {
  8689. + // Invalidate any pending idle injections, and reset the frame inject on idle.
  8690. + weak_factory_.InvalidateWeakPtrs();
  8691. + // We reset to inject on idle, because the frame can be reused (in the case of
  8692. + // navigation).
  8693. + should_run_idle_ = true;
  8694. +
  8695. + // Reset the frame if either |force_reset| is true, or if the manager is
  8696. + // keeping track of the state of the frame (in which case we need to clean it
  8697. + // up).
  8698. + if (force_reset || manager_->frame_statuses_.count(render_frame()) != 0)
  8699. + manager_->InvalidateForFrame(render_frame());
  8700. +}
  8701. +
  8702. +ScriptInjectionManager::ScriptInjectionManager(
  8703. + UserScriptSetManager* user_script_set_manager)
  8704. + : user_script_set_manager_(user_script_set_manager),
  8705. + user_script_set_manager_observer_(this) {
  8706. + user_script_set_manager_observer_.Add(user_script_set_manager_);
  8707. +}
  8708. +
  8709. +ScriptInjectionManager::~ScriptInjectionManager() {
  8710. + for (const auto& injection : pending_injections_)
  8711. + injection->invalidate_render_frame();
  8712. + for (const auto& injection : running_injections_)
  8713. + injection->invalidate_render_frame();
  8714. +}
  8715. +
  8716. +void ScriptInjectionManager::OnRenderFrameCreated(
  8717. + content::RenderFrame* render_frame) {
  8718. + rfo_helpers_.push_back(std::make_unique<RFOHelper>(render_frame, this));
  8719. + rfo_helpers_.back()->Initialize(); // commit @9f2aac4
  8720. +}
  8721. +
  8722. +void ScriptInjectionManager::OnInjectionFinished(
  8723. + ScriptInjection* injection) {
  8724. + auto iter =
  8725. + std::find_if(running_injections_.begin(), running_injections_.end(),
  8726. + [injection](const std::unique_ptr<ScriptInjection>& mode) {
  8727. + return injection == mode.get();
  8728. + });
  8729. + if (iter != running_injections_.end())
  8730. + running_injections_.erase(iter);
  8731. +}
  8732. +
  8733. +void ScriptInjectionManager::OnUserScriptsUpdated(
  8734. + const std::set<HostID>& changed_hosts) {
  8735. + for (auto iter = pending_injections_.begin();
  8736. + iter != pending_injections_.end();) {
  8737. + if (changed_hosts.count((*iter)->host_id()) > 0)
  8738. + iter = pending_injections_.erase(iter);
  8739. + else
  8740. + ++iter;
  8741. + }
  8742. +}
  8743. +
  8744. +void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
  8745. + for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
  8746. + if (iter->get() == helper) {
  8747. + rfo_helpers_.erase(iter);
  8748. + break;
  8749. + }
  8750. + }
  8751. +}
  8752. +
  8753. +void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
  8754. + // If the frame invalidated is the frame being injected into, we need to
  8755. + // note it.
  8756. + active_injection_frames_.erase(frame);
  8757. +
  8758. + for (auto iter = pending_injections_.begin();
  8759. + iter != pending_injections_.end();) {
  8760. + if ((*iter)->render_frame() == frame)
  8761. + iter = pending_injections_.erase(iter);
  8762. + else
  8763. + ++iter;
  8764. + }
  8765. +
  8766. + frame_statuses_.erase(frame);
  8767. +}
  8768. +
  8769. +void ScriptInjectionManager::StartInjectScripts(
  8770. + content::RenderFrame* frame,
  8771. + UserScript::RunLocation run_location) {
  8772. + auto iter = frame_statuses_.find(frame);
  8773. + // We also don't execute if we detect that the run location is somehow out of
  8774. + // order. This can happen if:
  8775. + // - The first run location reported for the frame isn't DOCUMENT_START, or
  8776. + // - The run location reported doesn't immediately follow the previous
  8777. + // reported run location.
  8778. + // We don't want to run because extensions may have requirements that scripts
  8779. + // running in an earlier run location have run by the time a later script
  8780. + // runs. Better to just not run.
  8781. + // Note that we check run_location > NextRunLocation() in the second clause
  8782. + // (as opposed to !=) because earlier signals (like DidCreateDocumentElement)
  8783. + // can happen multiple times, so we can receive earlier/equal run locations.
  8784. + if ((iter == frame_statuses_.end() &&
  8785. + run_location != UserScript::DOCUMENT_START) ||
  8786. + (iter != frame_statuses_.end() &&
  8787. + run_location > NextRunLocation(iter->second))) {
  8788. + // We also invalidate the frame, because the run order of pending injections
  8789. + // may also be bad.
  8790. + InvalidateForFrame(frame);
  8791. + return;
  8792. + } else if (iter != frame_statuses_.end() && iter->second >= run_location) {
  8793. + // Certain run location signals (like DidCreateDocumentElement) can happen
  8794. + // multiple times. Ignore the subsequent signals.
  8795. + return;
  8796. + }
  8797. +
  8798. + // Otherwise, all is right in the world, and we can get on with the
  8799. + // injections!
  8800. + frame_statuses_[frame] = run_location;
  8801. + InjectScripts(frame, run_location);
  8802. +}
  8803. +
  8804. +void ScriptInjectionManager::InjectScripts(
  8805. + content::RenderFrame* frame,
  8806. + UserScript::RunLocation run_location) {
  8807. + // Find any injections that want to run on the given frame.
  8808. + ScriptInjectionVector frame_injections;
  8809. + for (auto iter = pending_injections_.begin();
  8810. + iter != pending_injections_.end();) {
  8811. + if ((*iter)->render_frame() == frame) {
  8812. + frame_injections.push_back(std::move(*iter));
  8813. + iter = pending_injections_.erase(iter);
  8814. + } else {
  8815. + ++iter;
  8816. + }
  8817. + }
  8818. +
  8819. + // Add any injections for user scripts.
  8820. + int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
  8821. + user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
  8822. + run_location);
  8823. +
  8824. + // Note that we are running in |frame|.
  8825. + active_injection_frames_.insert(frame);
  8826. +
  8827. + ScriptsRunInfo scripts_run_info(frame, run_location);
  8828. +
  8829. + for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
  8830. + // It's possible for thScriptsRunInfoe frame to be invalidated in the course of injection
  8831. + // (if a script removes its own frame, for example). If this happens, abort.
  8832. + if (!active_injection_frames_.count(frame))
  8833. + break;
  8834. + std::unique_ptr<ScriptInjection> injection(std::move(*iter));
  8835. + iter = frame_injections.erase(iter);
  8836. + TryToInject(std::move(injection), run_location, &scripts_run_info);
  8837. + }
  8838. +
  8839. + // We are done running in the frame.
  8840. + active_injection_frames_.erase(frame);
  8841. +
  8842. + scripts_run_info.LogRun(activity_logging_enabled_);
  8843. +}
  8844. +
  8845. +void ScriptInjectionManager::TryToInject(
  8846. + std::unique_ptr<ScriptInjection> injection,
  8847. + UserScript::RunLocation run_location,
  8848. + ScriptsRunInfo* scripts_run_info) {
  8849. + // Try to inject the script. If the injection is waiting (i.e., for
  8850. + // permission), add it to the list of pending injections. If the injection
  8851. + // has blocked, add it to the list of running injections.
  8852. + // The Unretained below is safe because this object owns all the
  8853. + // ScriptInjections, so is guaranteed to outlive them.
  8854. + switch (injection->TryToInject(
  8855. + run_location, scripts_run_info,
  8856. + base::Bind(&ScriptInjectionManager::OnInjectionFinished,
  8857. + base::Unretained(this)))) {
  8858. + case ScriptInjection::INJECTION_WAITING:
  8859. + pending_injections_.push_back(std::move(injection));
  8860. + break;
  8861. + case ScriptInjection::INJECTION_BLOCKED:
  8862. + running_injections_.push_back(std::move(injection));
  8863. + break;
  8864. + case ScriptInjection::INJECTION_FINISHED:
  8865. + break;
  8866. + }
  8867. +}
  8868. +
  8869. +} // namespace extensions
  8870. diff --git a/components/user_scripts/renderer/script_injection_manager.h b/components/user_scripts/renderer/script_injection_manager.h
  8871. new file mode 100755
  8872. --- /dev/null
  8873. +++ b/components/user_scripts/renderer/script_injection_manager.h
  8874. @@ -0,0 +1,102 @@
  8875. +#include <stdint.h>
  8876. +
  8877. +#include <map>
  8878. +#include <set>
  8879. +#include <string>
  8880. +#include <vector>
  8881. +
  8882. +#include "base/callback.h"
  8883. +#include "base/macros.h"
  8884. +#include "base/scoped_observer.h"
  8885. +#include "../common/user_script.h"
  8886. +#include "script_injection.h"
  8887. +#include "user_script_set_manager.h"
  8888. +
  8889. +namespace user_scripts {
  8890. +
  8891. +// The ScriptInjectionManager manages extensions injecting scripts into frames
  8892. +// via both content/user scripts and tabs.executeScript(). It is responsible for
  8893. +// maintaining any pending injections awaiting permission or the appropriate
  8894. +// load point, and injecting them when ready.
  8895. +class ScriptInjectionManager : public UserScriptSetManager::Observer {
  8896. + public:
  8897. + explicit ScriptInjectionManager(
  8898. + UserScriptSetManager* user_script_set_manager);
  8899. + virtual ~ScriptInjectionManager();
  8900. +
  8901. + // Notifies that a new render view has been created.
  8902. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  8903. +
  8904. + // Removes pending injections of the unloaded extension.
  8905. + //void OnExtensionUnloaded(const std::string& extension_id);
  8906. +
  8907. + void set_activity_logging_enabled(bool enabled) {
  8908. + activity_logging_enabled_ = enabled;
  8909. + }
  8910. +
  8911. + private:
  8912. + // A RenderFrameObserver implementation which watches the various render
  8913. + // frames in order to notify the ScriptInjectionManager of different
  8914. + // document load states and IPCs.
  8915. + class RFOHelper;
  8916. +
  8917. + using FrameStatusMap =
  8918. + std::map<content::RenderFrame*, UserScript::RunLocation>;
  8919. +
  8920. + using ScriptInjectionVector = std::vector<std::unique_ptr<ScriptInjection>>;
  8921. +
  8922. + // Notifies that an injection has been finished.
  8923. + void OnInjectionFinished(ScriptInjection* injection);
  8924. +
  8925. + // UserScriptSetManager::Observer implementation.
  8926. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  8927. +
  8928. + // Notifies that an RFOHelper should be removed.
  8929. + void RemoveObserver(RFOHelper* helper);
  8930. +
  8931. + // Invalidate any pending tasks associated with |frame|.
  8932. + void InvalidateForFrame(content::RenderFrame* frame);
  8933. +
  8934. + // Starts the process to inject appropriate scripts into |frame|.
  8935. + void StartInjectScripts(content::RenderFrame* frame,
  8936. + UserScript::RunLocation run_location);
  8937. +
  8938. + // Actually injects the scripts into |frame|.
  8939. + void InjectScripts(content::RenderFrame* frame,
  8940. + UserScript::RunLocation run_location);
  8941. +
  8942. + // Try to inject and store injection if it has not finished.
  8943. + void TryToInject(std::unique_ptr<ScriptInjection> injection,
  8944. + UserScript::RunLocation run_location,
  8945. + ScriptsRunInfo* scripts_run_info);
  8946. +
  8947. + // The map of active web frames to their corresponding statuses. The
  8948. + // RunLocation of the frame corresponds to the last location that has ran.
  8949. + FrameStatusMap frame_statuses_;
  8950. +
  8951. + // The frames currently being injected into, so long as that frame is valid.
  8952. + std::set<content::RenderFrame*> active_injection_frames_;
  8953. +
  8954. + // The collection of RFOHelpers.
  8955. + std::vector<std::unique_ptr<RFOHelper>> rfo_helpers_;
  8956. +
  8957. + // The set of UserScripts associated with extensions. Owned by the Dispatcher.
  8958. + UserScriptSetManager* user_script_set_manager_;
  8959. +
  8960. + // Pending injections which are waiting for either the proper run location or
  8961. + // user consent.
  8962. + ScriptInjectionVector pending_injections_;
  8963. +
  8964. + // Running injections which are waiting for async callbacks from blink.
  8965. + ScriptInjectionVector running_injections_;
  8966. +
  8967. + // Whether or not dom activity should be logged for scripts injected.
  8968. + bool activity_logging_enabled_ = false;
  8969. +
  8970. + ScopedObserver<UserScriptSetManager, UserScriptSetManager::Observer>
  8971. + user_script_set_manager_observer_;
  8972. +
  8973. + DISALLOW_COPY_AND_ASSIGN(ScriptInjectionManager);
  8974. +};
  8975. +
  8976. +}
  8977. diff --git a/components/user_scripts/renderer/script_injector.h b/components/user_scripts/renderer/script_injector.h
  8978. new file mode 100755
  8979. --- /dev/null
  8980. +++ b/components/user_scripts/renderer/script_injector.h
  8981. @@ -0,0 +1,96 @@
  8982. +// Copyright 2014 The Chromium Authors. All rights reserved.
  8983. +// Use of this source code is governed by a BSD-style license that can be
  8984. +// found in the LICENSE file.
  8985. +
  8986. +#ifndef USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  8987. +#define USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  8988. +
  8989. +#include <memory>
  8990. +#include <vector>
  8991. +
  8992. +#include "../common/constants.h"
  8993. +#include "../common/user_script.h"
  8994. +#include "third_party/blink/public/web/web_script_source.h"
  8995. +
  8996. +class InjectionHost;
  8997. +
  8998. +namespace blink {
  8999. +class WebLocalFrame;
  9000. +}
  9001. +
  9002. +namespace user_scripts {
  9003. +
  9004. +// The pseudo-delegate class for a ScriptInjection that provides all necessary
  9005. +// information about how to inject the script, including what code to inject and
  9006. +// when (run location), but without any injection logic.
  9007. +class ScriptInjector {
  9008. + public:
  9009. + // The possible reasons for not injecting the script.
  9010. + enum InjectFailureReason {
  9011. + EXTENSION_REMOVED, // The extension was removed before injection.
  9012. + NOT_ALLOWED, // The script is not allowed to inject.
  9013. + WONT_INJECT // The injection won't inject because the user rejected
  9014. + // (or just did not accept) the injection.
  9015. + };
  9016. +
  9017. + virtual ~ScriptInjector() {}
  9018. +
  9019. + // Returns the script type of this particular injection.
  9020. + virtual UserScript::InjectionType script_type() const = 0;
  9021. +
  9022. + // Returns true if the script is running inside a user gesture.
  9023. + virtual bool IsUserGesture() const = 0;
  9024. +
  9025. + // Returns the CSS origin of this injection.
  9026. + virtual base::Optional<CSSOrigin> GetCssOrigin() const = 0;
  9027. +
  9028. + // Returns the key for this injection, if it's a CSS injection.
  9029. + virtual const base::Optional<std::string> GetInjectionKey() const = 0;
  9030. +
  9031. + // Returns true if the script expects results.
  9032. + virtual bool ExpectsResults() const = 0;
  9033. +
  9034. + // Returns true if the script should inject JS source at the given
  9035. + // |run_location|.
  9036. + virtual bool ShouldInjectJs(
  9037. + UserScript::RunLocation run_location,
  9038. + const std::set<std::string>& executing_scripts) const = 0;
  9039. +
  9040. + // Returns true if the script should inject CSS at the given |run_location|.
  9041. + virtual bool ShouldInjectCss(
  9042. + UserScript::RunLocation run_location,
  9043. + const std::set<std::string>& injected_stylesheets) const = 0;
  9044. +
  9045. + // Returns the javascript sources to inject at the given |run_location|.
  9046. + // Only called if ShouldInjectJs() is true.
  9047. + virtual std::vector<blink::WebScriptSource> GetJsSources(
  9048. + UserScript::RunLocation run_location,
  9049. + std::set<std::string>* executing_scripts,
  9050. + size_t* num_injected_js_scripts) const = 0;
  9051. +
  9052. + // Returns the css to inject at the given |run_location|.
  9053. + // Only called if ShouldInjectCss() is true.
  9054. + virtual std::vector<blink::WebString> GetCssSources(
  9055. + UserScript::RunLocation run_location,
  9056. + std::set<std::string>* injected_stylesheets,
  9057. + size_t* num_injected_stylesheets) const = 0;
  9058. +
  9059. + // Notifies the script that injection has completed, with a possibly-populated
  9060. + // list of results (depending on whether or not ExpectsResults() was true).
  9061. + // |render_frame| contains the render frame, or null if the frame was
  9062. + // invalidated.
  9063. + virtual void OnInjectionComplete(
  9064. + std::unique_ptr<base::Value> execution_result,
  9065. + UserScript::RunLocation run_location,
  9066. + content::RenderFrame* render_frame) = 0;
  9067. +
  9068. + // Notifies the script that injection will never occur.
  9069. + // |render_frame| contains the render frame, or null if the frame was
  9070. + // invalidated.
  9071. + virtual void OnWillNotInject(InjectFailureReason reason,
  9072. + content::RenderFrame* render_frame) = 0;
  9073. +};
  9074. +
  9075. +} // namespace extensions
  9076. +
  9077. +#endif // USERSCRIPTS_RENDERER_SCRIPT_INJECTOR_H_
  9078. diff --git a/components/user_scripts/renderer/scripts_run_info.cc b/components/user_scripts/renderer/scripts_run_info.cc
  9079. new file mode 100755
  9080. --- /dev/null
  9081. +++ b/components/user_scripts/renderer/scripts_run_info.cc
  9082. @@ -0,0 +1,31 @@
  9083. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9084. +// Use of this source code is governed by a BSD-style license that can be
  9085. +// found in the LICENSE file.
  9086. +
  9087. +#include "scripts_run_info.h"
  9088. +
  9089. +#include "base/metrics/histogram_macros.h"
  9090. +#include "content/public/renderer/render_frame.h"
  9091. +#include "content/public/renderer/render_thread.h"
  9092. +#include "script_context.h"
  9093. +#include "third_party/blink/public/web/web_local_frame.h"
  9094. +
  9095. +namespace user_scripts {
  9096. +
  9097. +ScriptsRunInfo::ScriptsRunInfo(content::RenderFrame* render_frame,
  9098. + UserScript::RunLocation location)
  9099. + : num_css(0u),
  9100. + num_js(0u),
  9101. + num_blocking_js(0u),
  9102. + routing_id_(render_frame->GetRoutingID()),
  9103. + run_location_(location),
  9104. + frame_url_(ScriptContext::GetDocumentLoaderURLForFrame(
  9105. + render_frame->GetWebFrame())) {}
  9106. +
  9107. +ScriptsRunInfo::~ScriptsRunInfo() {
  9108. +}
  9109. +
  9110. +void ScriptsRunInfo::LogRun(bool send_script_activity) {
  9111. +}
  9112. +
  9113. +} // namespace extensions
  9114. diff --git a/components/user_scripts/renderer/scripts_run_info.h b/components/user_scripts/renderer/scripts_run_info.h
  9115. new file mode 100755
  9116. --- /dev/null
  9117. +++ b/components/user_scripts/renderer/scripts_run_info.h
  9118. @@ -0,0 +1,70 @@
  9119. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9120. +// Use of this source code is governed by a BSD-style license that can be
  9121. +// found in the LICENSE file.
  9122. +
  9123. +#ifndef USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9124. +#define USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9125. +
  9126. +#include <stddef.h>
  9127. +
  9128. +#include <map>
  9129. +#include <set>
  9130. +#include <string>
  9131. +
  9132. +#include "base/macros.h"
  9133. +#include "base/timer/elapsed_timer.h"
  9134. +#include "../common/user_script.h"
  9135. +
  9136. +namespace content {
  9137. +class RenderFrame;
  9138. +}
  9139. +
  9140. +namespace user_scripts {
  9141. +
  9142. +// A struct containing information about a script run.
  9143. +struct ScriptsRunInfo {
  9144. + // Map of extensions IDs to the executing script paths.
  9145. + typedef std::map<std::string, std::set<std::string> > ExecutingScriptsMap;
  9146. +
  9147. + ScriptsRunInfo(content::RenderFrame* render_frame,
  9148. + UserScript::RunLocation location);
  9149. + ~ScriptsRunInfo();
  9150. +
  9151. + // The number of CSS scripts injected.
  9152. + size_t num_css;
  9153. + // The number of JS scripts injected.
  9154. + size_t num_js;
  9155. + // The number of blocked JS scripts injected.
  9156. + size_t num_blocking_js;
  9157. + // A map of extension ids to executing script paths.
  9158. + ExecutingScriptsMap executing_scripts;
  9159. + // A map of extension ids to injected stylesheet paths.
  9160. + ExecutingScriptsMap injected_stylesheets;
  9161. + // The elapsed time since the ScriptsRunInfo was constructed.
  9162. + base::ElapsedTimer timer;
  9163. +
  9164. + // Log information about a given script run. If |send_script_activity| is
  9165. + // true, this also informs the browser of the script run.
  9166. + void LogRun(bool send_script_activity);
  9167. +
  9168. + static void LogLongInjectionTaskTime(UserScript::RunLocation run_location,
  9169. + const base::TimeDelta& elapsed);
  9170. +
  9171. + private:
  9172. + // The routinig id to use to notify the browser of any injections. Since the
  9173. + // frame may be deleted in injection, we don't hold on to a reference to it
  9174. + // directly.
  9175. + int routing_id_;
  9176. +
  9177. + // The run location at which injection is happening.
  9178. + UserScript::RunLocation run_location_;
  9179. +
  9180. + // The url of the frame, preserved for the same reason as the routing id.
  9181. + GURL frame_url_;
  9182. +
  9183. + DISALLOW_COPY_AND_ASSIGN(ScriptsRunInfo);
  9184. +};
  9185. +
  9186. +} // namespace extensions
  9187. +
  9188. +#endif // USERSCRIPTS_RENDERER_SCRIPTS_RUN_INFO_H_
  9189. diff --git a/components/user_scripts/renderer/user_script_injector.cc b/components/user_scripts/renderer/user_script_injector.cc
  9190. new file mode 100755
  9191. --- /dev/null
  9192. +++ b/components/user_scripts/renderer/user_script_injector.cc
  9193. @@ -0,0 +1,228 @@
  9194. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9195. +// Use of this source code is governed by a BSD-style license that can be
  9196. +// found in the LICENSE file.
  9197. +
  9198. +#include "user_script_injector.h"
  9199. +
  9200. +#include <tuple>
  9201. +#include <vector>
  9202. +
  9203. +#include "base/logging.h"
  9204. +#include "base/lazy_instance.h"
  9205. +#include "content/public/common/url_constants.h"
  9206. +#include "content/public/renderer/render_frame.h"
  9207. +#include "content/public/renderer/render_thread.h"
  9208. +#include "content/public/renderer/render_view.h"
  9209. +#include "components/user_scripts/renderer/grit/user_scripts_renderer_resources.h"
  9210. +#include "injection_host.h"
  9211. +#include "script_context.h"
  9212. +#include "scripts_run_info.h"
  9213. +#include "third_party/blink/public/web/web_document.h"
  9214. +#include "third_party/blink/public/web/web_local_frame.h"
  9215. +#include "third_party/blink/public/web/web_script_source.h"
  9216. +#include "ui/base/resource/resource_bundle.h"
  9217. +#include "url/gurl.h"
  9218. +
  9219. +namespace user_scripts {
  9220. +
  9221. +namespace {
  9222. +
  9223. +struct RoutingInfoKey {
  9224. + int routing_id;
  9225. + int script_id;
  9226. +
  9227. + RoutingInfoKey(int routing_id, int script_id)
  9228. + : routing_id(routing_id), script_id(script_id) {}
  9229. +
  9230. + bool operator<(const RoutingInfoKey& other) const {
  9231. + return std::tie(routing_id, script_id) <
  9232. + std::tie(other.routing_id, other.script_id);
  9233. + }
  9234. +};
  9235. +
  9236. +using RoutingInfoMap = std::map<RoutingInfoKey, bool>;
  9237. +
  9238. +// A map records whether a given |script_id| from a webview-added user script
  9239. +// is allowed to inject on the render of given |routing_id|.
  9240. +// Once a script is added, the decision of whether or not allowed to inject
  9241. +// won't be changed.
  9242. +// After removed by the webview, the user scipt will also be removed
  9243. +// from the render. Therefore, there won't be any query from the same
  9244. +// |script_id| and |routing_id| pair.
  9245. +// base::LazyInstance<RoutingInfoMap>::DestructorAtExit g_routing_info_map =
  9246. +// LAZY_INSTANCE_INITIALIZER;
  9247. +
  9248. +// Greasemonkey API source that is injected with the scripts.
  9249. +struct GreasemonkeyApiJsString {
  9250. + GreasemonkeyApiJsString();
  9251. + blink::WebScriptSource GetSource() const;
  9252. +
  9253. + private:
  9254. + blink::WebString source_;
  9255. +};
  9256. +
  9257. +// The below constructor, monstrous as it is, just makes a WebScriptSource from
  9258. +// the GreasemonkeyApiJs resource.
  9259. +GreasemonkeyApiJsString::GreasemonkeyApiJsString() {
  9260. + std::string greasemonky_api_js(
  9261. + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  9262. + IDR_GREASEMONKEY_API_JS));
  9263. + source_ = blink::WebString::FromUTF8(greasemonky_api_js);
  9264. +}
  9265. +
  9266. +blink::WebScriptSource GreasemonkeyApiJsString::GetSource() const {
  9267. + return blink::WebScriptSource(source_);
  9268. +}
  9269. +
  9270. +base::LazyInstance<GreasemonkeyApiJsString>::Leaky g_greasemonkey_api =
  9271. + LAZY_INSTANCE_INITIALIZER;
  9272. +
  9273. +bool ShouldInjectScripts(const UserScript::FileList& scripts,
  9274. + const std::set<std::string>& injected_files) {
  9275. + for (const std::unique_ptr<UserScript::File>& file : scripts) {
  9276. + // Check if the script is already injected.
  9277. + if (injected_files.count(file->url().path()) == 0) {
  9278. + return true;
  9279. + }
  9280. + }
  9281. + return false;
  9282. +}
  9283. +
  9284. +} // namespace
  9285. +
  9286. +UserScriptInjector::UserScriptInjector(const UserScript* script,
  9287. + UserScriptSet* script_list)
  9288. + : script_(script),
  9289. + user_script_set_(script_list),
  9290. + script_id_(script_->id()),
  9291. + user_script_set_observer_(this) {
  9292. + user_script_set_observer_.Add(script_list);
  9293. +}
  9294. +
  9295. +UserScriptInjector::~UserScriptInjector() {
  9296. +}
  9297. +
  9298. +void UserScriptInjector::OnUserScriptsUpdated(
  9299. + const std::set<HostID>& changed_hosts,
  9300. + const UserScriptList& scripts) {
  9301. + // When user scripts are updated, all the old script pointers are invalidated.
  9302. + script_ = nullptr;
  9303. + // If the host causing this injection changed, then this injection
  9304. + // will be removed, and there's no guarantee the backing script still exists.
  9305. + // if (changed_hosts.count(host_id_) > 0)
  9306. + // return;
  9307. +
  9308. + for (const std::unique_ptr<UserScript>& script : scripts) {
  9309. + if (script->id() == script_id_) {
  9310. + script_ = script.get();
  9311. + break;
  9312. + }
  9313. + }
  9314. + // If |host_id_| wasn't in |changed_hosts|, then the script for this injection
  9315. + // should be guaranteed to exist.
  9316. + DCHECK(script_);
  9317. +}
  9318. +
  9319. +UserScript::InjectionType UserScriptInjector::script_type() const {
  9320. + return UserScript::CONTENT_SCRIPT;
  9321. +}
  9322. +
  9323. +bool UserScriptInjector::IsUserGesture() const {
  9324. + return false;
  9325. +}
  9326. +
  9327. +bool UserScriptInjector::ExpectsResults() const {
  9328. + return false;
  9329. +}
  9330. +
  9331. +base::Optional<CSSOrigin> UserScriptInjector::GetCssOrigin() const {
  9332. + return base::nullopt;
  9333. +}
  9334. +
  9335. +const base::Optional<std::string> UserScriptInjector::GetInjectionKey() const {
  9336. + return base::nullopt;
  9337. +}
  9338. +
  9339. +bool UserScriptInjector::ShouldInjectJs(
  9340. + UserScript::RunLocation run_location,
  9341. + const std::set<std::string>& executing_scripts) const {
  9342. + return script_ && script_->run_location() == run_location &&
  9343. + !script_->js_scripts().empty() &&
  9344. + ShouldInjectScripts(script_->js_scripts(), executing_scripts);
  9345. +}
  9346. +
  9347. +bool UserScriptInjector::ShouldInjectCss(
  9348. + UserScript::RunLocation run_location,
  9349. + const std::set<std::string>& injected_stylesheets) const {
  9350. + return script_ && run_location == UserScript::DOCUMENT_START &&
  9351. + !script_->css_scripts().empty() &&
  9352. + ShouldInjectScripts(script_->css_scripts(), injected_stylesheets);
  9353. +}
  9354. +
  9355. +std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
  9356. + UserScript::RunLocation run_location,
  9357. + std::set<std::string>* executing_scripts,
  9358. + size_t* num_injected_js_scripts) const {
  9359. + DCHECK(script_);
  9360. + std::vector<blink::WebScriptSource> sources;
  9361. +
  9362. + DCHECK_EQ(script_->run_location(), run_location);
  9363. +
  9364. + const UserScript::FileList& js_scripts = script_->js_scripts();
  9365. + sources.reserve(js_scripts.size() +
  9366. + (script_->emulate_greasemonkey() ? 1 : 0));
  9367. + // Emulate Greasemonkey API for scripts that were converted to extension
  9368. + // user scripts.
  9369. + if (script_->emulate_greasemonkey())
  9370. + sources.push_back(g_greasemonkey_api.Get().GetSource());
  9371. + for (const std::unique_ptr<UserScript::File>& file : js_scripts) {
  9372. + const GURL& script_url = file->url();
  9373. + // Check if the script is already injected.
  9374. + if (executing_scripts->count(script_url.path()) != 0)
  9375. + continue;
  9376. +
  9377. + sources.push_back(blink::WebScriptSource(
  9378. + user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
  9379. + script_url));
  9380. +
  9381. + (*num_injected_js_scripts) += 1;
  9382. + executing_scripts->insert(script_url.path());
  9383. + }
  9384. +
  9385. + return sources;
  9386. +}
  9387. +
  9388. +std::vector<blink::WebString> UserScriptInjector::GetCssSources(
  9389. + UserScript::RunLocation run_location,
  9390. + std::set<std::string>* injected_stylesheets,
  9391. + size_t* num_injected_stylesheets) const {
  9392. + DCHECK(script_);
  9393. + DCHECK_EQ(UserScript::DOCUMENT_START, run_location);
  9394. +
  9395. + std::vector<blink::WebString> sources;
  9396. +
  9397. + const UserScript::FileList& css_scripts = script_->css_scripts();
  9398. + sources.reserve(css_scripts.size());
  9399. + for (const std::unique_ptr<UserScript::File>& file : script_->css_scripts()) {
  9400. + const std::string& stylesheet_path = file->url().path();
  9401. + // Check if the stylesheet is already injected.
  9402. + if (injected_stylesheets->count(stylesheet_path) != 0)
  9403. + continue;
  9404. +
  9405. + sources.push_back(user_script_set_->GetCssSource(*file));
  9406. + (*num_injected_stylesheets) += 1;
  9407. + injected_stylesheets->insert(stylesheet_path);
  9408. + }
  9409. + return sources;
  9410. +}
  9411. +
  9412. +void UserScriptInjector::OnInjectionComplete(
  9413. + std::unique_ptr<base::Value> execution_result,
  9414. + UserScript::RunLocation run_location,
  9415. + content::RenderFrame* render_frame) {}
  9416. +
  9417. +void UserScriptInjector::OnWillNotInject(InjectFailureReason reason,
  9418. + content::RenderFrame* render_frame) {
  9419. +}
  9420. +
  9421. +} // namespace extensions
  9422. diff --git a/components/user_scripts/renderer/user_script_injector.h b/components/user_scripts/renderer/user_script_injector.h
  9423. new file mode 100755
  9424. --- /dev/null
  9425. +++ b/components/user_scripts/renderer/user_script_injector.h
  9426. @@ -0,0 +1,86 @@
  9427. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9428. +// Use of this source code is governed by a BSD-style license that can be
  9429. +// found in the LICENSE file.
  9430. +
  9431. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9432. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9433. +
  9434. +#include <memory>
  9435. +#include <string>
  9436. +
  9437. +#include "base/macros.h"
  9438. +#include "base/scoped_observer.h"
  9439. +#include "../common/user_script.h"
  9440. +#include "script_injection.h"
  9441. +#include "user_script_set.h"
  9442. +
  9443. +class InjectionHost;
  9444. +
  9445. +namespace blink {
  9446. +class WebLocalFrame;
  9447. +}
  9448. +
  9449. +namespace user_scripts {
  9450. +
  9451. +// A ScriptInjector for UserScripts.
  9452. +class UserScriptInjector : public ScriptInjector,
  9453. + public UserScriptSet::Observer {
  9454. + public:
  9455. + UserScriptInjector(const UserScript* user_script,
  9456. + UserScriptSet* user_script_set);
  9457. + ~UserScriptInjector() override;
  9458. +
  9459. + private:
  9460. + // UserScriptSet::Observer implementation.
  9461. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9462. + const UserScriptList& scripts) override;
  9463. +
  9464. + // ScriptInjector implementation.
  9465. + UserScript::InjectionType script_type() const override;
  9466. + bool IsUserGesture() const override;
  9467. + base::Optional<CSSOrigin> GetCssOrigin() const override;
  9468. + const base::Optional<std::string> GetInjectionKey() const override;
  9469. + bool ExpectsResults() const override;
  9470. + bool ShouldInjectJs(
  9471. + UserScript::RunLocation run_location,
  9472. + const std::set<std::string>& executing_scripts) const override;
  9473. + bool ShouldInjectCss(
  9474. + UserScript::RunLocation run_location,
  9475. + const std::set<std::string>& injected_stylesheets) const override;
  9476. + std::vector<blink::WebScriptSource> GetJsSources(
  9477. + UserScript::RunLocation run_location,
  9478. + std::set<std::string>* executing_scripts,
  9479. + size_t* num_injected_js_scripts) const override;
  9480. + std::vector<blink::WebString> GetCssSources(
  9481. + UserScript::RunLocation run_location,
  9482. + std::set<std::string>* injected_stylesheets,
  9483. + size_t* num_injected_stylesheets) const override;
  9484. + void OnInjectionComplete(std::unique_ptr<base::Value> execution_result,
  9485. + UserScript::RunLocation run_location,
  9486. + content::RenderFrame* render_frame) override;
  9487. + void OnWillNotInject(InjectFailureReason reason,
  9488. + content::RenderFrame* render_frame) override;
  9489. +
  9490. + // The associated user script. Owned by the UserScriptInjector that created
  9491. + // this object.
  9492. + const UserScript* script_;
  9493. +
  9494. + // The UserScriptSet that eventually owns the UserScript this
  9495. + // UserScriptInjector points to.
  9496. + // Outlives |this|.
  9497. + UserScriptSet* const user_script_set_;
  9498. +
  9499. + // The id of the associated user script. We cache this because when we update
  9500. + // the |script_| associated with this injection, the old referance may be
  9501. + // deleted.
  9502. + int script_id_;
  9503. +
  9504. + ScopedObserver<UserScriptSet, UserScriptSet::Observer>
  9505. + user_script_set_observer_;
  9506. +
  9507. + DISALLOW_COPY_AND_ASSIGN(UserScriptInjector);
  9508. +};
  9509. +
  9510. +} // namespace extensions
  9511. +
  9512. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_INJECTOR_H_
  9513. diff --git a/components/user_scripts/renderer/user_script_set.cc b/components/user_scripts/renderer/user_script_set.cc
  9514. new file mode 100755
  9515. --- /dev/null
  9516. +++ b/components/user_scripts/renderer/user_script_set.cc
  9517. @@ -0,0 +1,259 @@
  9518. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9519. +// Use of this source code is governed by a BSD-style license that can be
  9520. +// found in the LICENSE file.
  9521. +
  9522. +#include "user_script_set.h"
  9523. +
  9524. +#include <stddef.h>
  9525. +
  9526. +#include <utility>
  9527. +
  9528. +#include "base/logging.h"
  9529. +#include "base/debug/alias.h"
  9530. +#include "base/memory/ref_counted.h"
  9531. +#include "base/strings/strcat.h"
  9532. +#include "content/public/common/url_constants.h"
  9533. +#include "content/public/renderer/render_frame.h"
  9534. +#include "content/public/renderer/render_thread.h"
  9535. +#include "injection_host.h"
  9536. +#include "script_context.h"
  9537. +#include "script_injection.h"
  9538. +#include "user_script_injector.h"
  9539. +#include "web_ui_injection_host.h"
  9540. +#include "third_party/blink/public/web/web_document.h"
  9541. +#include "third_party/blink/public/web/web_local_frame.h"
  9542. +#include "url/gurl.h"
  9543. +#include "../common/user_scripts_features.h"
  9544. +
  9545. +namespace user_scripts {
  9546. +
  9547. +namespace {
  9548. +
  9549. +// These two strings are injected before and after the Greasemonkey API and
  9550. +// user script to wrap it in an anonymous scope.
  9551. +const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
  9552. +const char kUserScriptTail[] = "\n})(window);";
  9553. +// Maximum number of total content scripts we allow (across all extensions).
  9554. +// The limit exists to diagnose https://crbug.com/723381. The number is
  9555. +// arbitrarily chosen.
  9556. +// TODO(lazyboy): Remove when the bug is fixed.
  9557. +const uint32_t kNumScriptsArbitraryMax = 100000u;
  9558. +
  9559. +GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
  9560. + GURL data_source_url = ScriptContext::GetDocumentLoaderURLForFrame(frame);
  9561. + if (!data_source_url.is_empty() && frame->IsViewSourceModeEnabled()) {
  9562. + data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
  9563. + data_source_url.spec());
  9564. + }
  9565. +
  9566. + return data_source_url;
  9567. +}
  9568. +
  9569. +} // namespace
  9570. +
  9571. +UserScriptSet::UserScriptSet() {}
  9572. +
  9573. +UserScriptSet::~UserScriptSet() {
  9574. +}
  9575. +
  9576. +void UserScriptSet::AddObserver(Observer* observer) {
  9577. + observers_.AddObserver(observer);
  9578. +}
  9579. +
  9580. +void UserScriptSet::RemoveObserver(Observer* observer) {
  9581. + observers_.RemoveObserver(observer);
  9582. +}
  9583. +
  9584. +void UserScriptSet::GetInjections(
  9585. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9586. + content::RenderFrame* render_frame,
  9587. + int tab_id,
  9588. + UserScript::RunLocation run_location,
  9589. + bool log_activity) {
  9590. + GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
  9591. + for (const std::unique_ptr<UserScript>& script : scripts_) {
  9592. + std::unique_ptr<ScriptInjection> injection = GetInjectionForScript(
  9593. + script.get(), render_frame, tab_id, run_location, document_url,
  9594. + /* is_declarative, */ log_activity);
  9595. + if (injection.get())
  9596. + injections->push_back(std::move(injection));
  9597. + }
  9598. +}
  9599. +
  9600. +bool UserScriptSet::UpdateUserScripts(
  9601. + base::ReadOnlySharedMemoryRegion shared_memory,
  9602. + const std::set<HostID>& changed_hosts,
  9603. + bool whitelisted_only) {
  9604. + bool only_inject_incognito = false;
  9605. + //ExtensionsRendererClient::Get()->IsIncognitoProcess();
  9606. +
  9607. + // Create the shared memory mapping.
  9608. + shared_memory_mapping_ = shared_memory.Map();
  9609. + if (!shared_memory.IsValid())
  9610. + return false;
  9611. +
  9612. + // First get the size of the memory block.
  9613. + const base::Pickle::Header* pickle_header =
  9614. + shared_memory_mapping_.GetMemoryAs<base::Pickle::Header>();
  9615. + if (!pickle_header)
  9616. + return false;
  9617. +
  9618. + // Now read in the rest of the block.
  9619. + size_t pickle_size =
  9620. + sizeof(base::Pickle::Header) + pickle_header->payload_size;
  9621. +
  9622. + // Unpickle scripts.
  9623. + uint32_t num_scripts = 0;
  9624. + auto memory = shared_memory_mapping_.GetMemoryAsSpan<char>(pickle_size);
  9625. + if (!memory.size())
  9626. + return false;
  9627. +
  9628. + base::Pickle pickle(memory.data(), pickle_size);
  9629. + base::PickleIterator iter(pickle);
  9630. + base::debug::Alias(&pickle_size);
  9631. + CHECK(iter.ReadUInt32(&num_scripts));
  9632. +
  9633. + // Sometimes the shared memory contents seem to be corrupted
  9634. + // (https://crbug.com/723381). Set an arbitrary max limit to the number of
  9635. + // scripts so that we don't add OOM noise to crash reports.
  9636. + CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
  9637. +
  9638. + scripts_.clear();
  9639. + script_sources_.clear();
  9640. + scripts_.reserve(num_scripts);
  9641. + for (uint32_t i = 0; i < num_scripts; ++i) {
  9642. + std::unique_ptr<UserScript> script(new UserScript());
  9643. + script->Unpickle(pickle, &iter);
  9644. +
  9645. + // Note that this is a pointer into shared memory. We don't own it. It gets
  9646. + // cleared up when the last renderer or browser process drops their
  9647. + // reference to the shared memory.
  9648. + for (size_t j = 0; j < script->js_scripts().size(); ++j) {
  9649. + const char* body = NULL;
  9650. + int body_length = 0;
  9651. + CHECK(iter.ReadData(&body, &body_length));
  9652. + script->js_scripts()[j]->set_external_content(
  9653. + base::StringPiece(body, body_length));
  9654. + }
  9655. + for (size_t j = 0; j < script->css_scripts().size(); ++j) {
  9656. + const char* body = NULL;
  9657. + int body_length = 0;
  9658. + CHECK(iter.ReadData(&body, &body_length));
  9659. + script->css_scripts()[j]->set_external_content(
  9660. + base::StringPiece(body, body_length));
  9661. + }
  9662. +
  9663. + if (only_inject_incognito && !script->is_incognito_enabled())
  9664. + continue; // This script shouldn't run in an incognito tab.
  9665. +
  9666. + scripts_.push_back(std::move(script));
  9667. + }
  9668. +
  9669. + for (auto& observer : observers_)
  9670. + observer.OnUserScriptsUpdated(changed_hosts, scripts_);
  9671. + return true;
  9672. +}
  9673. +
  9674. +void UserScriptSet::AddScript(std::unique_ptr<UserScript> script) {
  9675. + scripts_.push_back(std::move(script));
  9676. +}
  9677. +
  9678. +std::unique_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
  9679. + const UserScript* script,
  9680. + content::RenderFrame* render_frame,
  9681. + int tab_id,
  9682. + UserScript::RunLocation run_location,
  9683. + const GURL& document_url,
  9684. + //bool is_declarative,
  9685. + bool log_activity) {
  9686. + std::unique_ptr<ScriptInjection> injection;
  9687. + std::unique_ptr<const InjectionHost> injection_host;
  9688. + blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  9689. +
  9690. + const HostID& host_id = script->host_id();
  9691. + injection_host.reset(new WebUIInjectionHost(host_id));
  9692. +
  9693. + GURL effective_document_url =
  9694. + ScriptContext::GetEffectiveDocumentURLForInjection(
  9695. + web_frame, document_url, script->match_origin_as_fallback());
  9696. +
  9697. + bool is_subframe = web_frame->Parent();
  9698. + if (!script->MatchesDocument(effective_document_url, is_subframe)) {
  9699. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9700. + LOG(INFO) << "UserScripts: No Match name=" << script->name() << " " <<
  9701. + "url=" << effective_document_url.spec();
  9702. + return injection;
  9703. + }
  9704. +
  9705. + std::unique_ptr<ScriptInjector> injector(
  9706. + new UserScriptInjector(script, this));
  9707. +
  9708. + bool inject_css = !script->css_scripts().empty() &&
  9709. + run_location == UserScript::DOCUMENT_START;
  9710. + bool inject_js =
  9711. + !script->js_scripts().empty() && script->run_location() == run_location;
  9712. + if (inject_css || inject_js) {
  9713. + injection.reset(new ScriptInjection(std::move(injector), render_frame,
  9714. + std::move(injection_host), run_location,
  9715. + log_activity));
  9716. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9717. + LOG(INFO) << "UserScripts: Match name=" << script->name() << " " <<
  9718. + "url=" << effective_document_url.spec();
  9719. + } else {
  9720. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts)) {
  9721. + if (script->run_location() != run_location)
  9722. + LOG(INFO) << "UserScripts: run location for name=" << script->name() <<
  9723. + "current " << run_location << " " <<
  9724. + "need " << script->run_location();
  9725. + else
  9726. + LOG(INFO) << "UserScripts: Match but no run name=" << script->name() << " " <<
  9727. + "url=" << effective_document_url.spec();
  9728. + }
  9729. + }
  9730. + return injection;
  9731. +}
  9732. +
  9733. +blink::WebString UserScriptSet::GetJsSource(const UserScript::File& file,
  9734. + bool emulate_greasemonkey) {
  9735. + const GURL& url = file.url();
  9736. + auto iter = script_sources_.find(url);
  9737. + if (iter != script_sources_.end()) {
  9738. + return iter->second;
  9739. + }
  9740. +
  9741. + base::StringPiece script_content = file.GetContent();
  9742. + blink::WebString source;
  9743. + if (emulate_greasemonkey) {
  9744. + // We add this dumb function wrapper for user scripts to emulate what
  9745. + // Greasemonkey does. |script_content| becomes:
  9746. + // concat(kUserScriptHead, script_content, kUserScriptTail).
  9747. + std::string content =
  9748. + base::StrCat({kUserScriptHead, script_content, kUserScriptTail});
  9749. + source = blink::WebString::FromUTF8(content);
  9750. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9751. + LOG(INFO) << "UserScripts: Injecting w/greasemonkey " << file.url();
  9752. + } else {
  9753. + source = blink::WebString::FromUTF8(script_content.data(),
  9754. + script_content.length());
  9755. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9756. + LOG(INFO) << "UserScripts: Injecting " << file.url();
  9757. + }
  9758. + script_sources_[url] = source;
  9759. + return source;
  9760. +}
  9761. +
  9762. +blink::WebString UserScriptSet::GetCssSource(const UserScript::File& file) {
  9763. + const GURL& url = file.url();
  9764. + auto iter = script_sources_.find(url);
  9765. + if (iter != script_sources_.end())
  9766. + return iter->second;
  9767. +
  9768. + base::StringPiece script_content = file.GetContent();
  9769. + return script_sources_
  9770. + .insert(std::make_pair(
  9771. + url, blink::WebString::FromUTF8(script_content.data(),
  9772. + script_content.length())))
  9773. + .first->second;
  9774. +}
  9775. +
  9776. +} // namespace extensions
  9777. diff --git a/components/user_scripts/renderer/user_script_set.h b/components/user_scripts/renderer/user_script_set.h
  9778. new file mode 100755
  9779. --- /dev/null
  9780. +++ b/components/user_scripts/renderer/user_script_set.h
  9781. @@ -0,0 +1,102 @@
  9782. +// Copyright 2014 The Chromium Authors. All rights reserved.
  9783. +// Use of this source code is governed by a BSD-style license that can be
  9784. +// found in the LICENSE file.
  9785. +
  9786. +#ifndef USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9787. +#define USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9788. +
  9789. +#include <map>
  9790. +#include <memory>
  9791. +#include <set>
  9792. +#include <string>
  9793. +#include <vector>
  9794. +
  9795. +#include "base/macros.h"
  9796. +#include "base/memory/read_only_shared_memory_region.h"
  9797. +#include "base/observer_list.h"
  9798. +#include "../common/user_script.h"
  9799. +#include "third_party/blink/public/platform/web_string.h"
  9800. +
  9801. +class GURL;
  9802. +
  9803. +namespace content {
  9804. +class RenderFrame;
  9805. +}
  9806. +
  9807. +namespace user_scripts {
  9808. +class ScriptInjection;
  9809. +
  9810. +// The UserScriptSet is a collection of UserScripts which knows how to update
  9811. +// itself from SharedMemory and create ScriptInjections for UserScripts to
  9812. +// inject on a page.
  9813. +class UserScriptSet {
  9814. + public:
  9815. + class Observer {
  9816. + public:
  9817. + // Called when the set of user scripts is updated. |changed_hosts| contains
  9818. + // the hosts whose scripts have been altered. Note that *all* script objects
  9819. + // are invalidated, even if they aren't in |changed_hosts|.
  9820. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts,
  9821. + const UserScriptList& scripts) = 0;
  9822. + };
  9823. +
  9824. + UserScriptSet();
  9825. + ~UserScriptSet();
  9826. +
  9827. + // Adds or removes observers.
  9828. + void AddObserver(Observer* observer);
  9829. + void RemoveObserver(Observer* observer);
  9830. + void AddScript(std::unique_ptr<UserScript> script);
  9831. +
  9832. + // Append any ScriptInjections that should run on the given |render_frame| and
  9833. + // |tab_id|, at the given |run_location|, to |injections|.
  9834. + // |extensions| is passed in to verify the corresponding extension is still
  9835. + // valid.
  9836. + void GetInjections(std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9837. + content::RenderFrame* render_frame,
  9838. + int tab_id,
  9839. + UserScript::RunLocation run_location,
  9840. + bool log_activity);
  9841. +
  9842. + // Updates scripts given the shared memory region containing user scripts.
  9843. + // Returns true if the scripts were successfully updated.
  9844. + bool UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
  9845. + const std::set<HostID>& changed_hosts,
  9846. + bool whitelisted_only);
  9847. +
  9848. + // Returns the contents of a script file.
  9849. + // Note that copying is cheap as this uses WebString.
  9850. + blink::WebString GetJsSource(const UserScript::File& file,
  9851. + bool emulate_greasemonkey);
  9852. + blink::WebString GetCssSource(const UserScript::File& file);
  9853. +
  9854. + private:
  9855. + // Returns a new ScriptInjection for the given |script| to execute in the
  9856. + // |render_frame|, or NULL if the script should not execute.
  9857. + std::unique_ptr<ScriptInjection> GetInjectionForScript(
  9858. + const UserScript* script,
  9859. + content::RenderFrame* render_frame,
  9860. + int tab_id,
  9861. + UserScript::RunLocation run_location,
  9862. + const GURL& document_url,
  9863. + //bool is_declarative,
  9864. + bool log_activity);
  9865. +
  9866. + // Shared memory mapping containing raw script data.
  9867. + base::ReadOnlySharedMemoryMapping shared_memory_mapping_;
  9868. +
  9869. + // The UserScripts this injector manages.
  9870. + UserScriptList scripts_;
  9871. +
  9872. + // Map of user script file url -> source.
  9873. + std::map<GURL, blink::WebString> script_sources_;
  9874. +
  9875. + // The associated observers.
  9876. + base::ObserverList<Observer>::Unchecked observers_;
  9877. +
  9878. + DISALLOW_COPY_AND_ASSIGN(UserScriptSet);
  9879. +};
  9880. +
  9881. +} // namespace extensions
  9882. +
  9883. +#endif // USERSCRIPTS_RENDERER_USER_SCRIPT_SET_H_
  9884. diff --git a/components/user_scripts/renderer/user_script_set_manager.cc b/components/user_scripts/renderer/user_script_set_manager.cc
  9885. new file mode 100755
  9886. --- /dev/null
  9887. +++ b/components/user_scripts/renderer/user_script_set_manager.cc
  9888. @@ -0,0 +1,77 @@
  9889. +#include "user_script_set_manager.h"
  9890. +
  9891. +#include "base/logging.h"
  9892. +#include "content/public/renderer/render_thread.h"
  9893. +#include "../common/host_id.h"
  9894. +#include "../common/extension_messages.h"
  9895. +#include "../common/user_scripts_features.h"
  9896. +#include "user_script_set.h"
  9897. +
  9898. +namespace user_scripts {
  9899. +
  9900. +UserScriptSetManager::UserScriptSetManager() {
  9901. + content::RenderThread::Get()->AddObserver(this);
  9902. +}
  9903. +
  9904. +UserScriptSetManager::~UserScriptSetManager() {
  9905. +}
  9906. +
  9907. +void UserScriptSetManager::AddObserver(Observer* observer) {
  9908. + observers_.AddObserver(observer);
  9909. +}
  9910. +
  9911. +void UserScriptSetManager::RemoveObserver(Observer* observer) {
  9912. + observers_.RemoveObserver(observer);
  9913. +}
  9914. +
  9915. +bool UserScriptSetManager::OnControlMessageReceived(
  9916. + const IPC::Message& message) {
  9917. + bool handled = true;
  9918. + IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
  9919. + IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
  9920. + IPC_MESSAGE_UNHANDLED(handled = false)
  9921. + IPC_END_MESSAGE_MAP()
  9922. + return handled;
  9923. +}
  9924. +
  9925. +void UserScriptSetManager::GetAllInjections(
  9926. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  9927. + content::RenderFrame* render_frame,
  9928. + int tab_id,
  9929. + UserScript::RunLocation run_location) {
  9930. +
  9931. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  9932. + LOG(INFO) << "UserScripts: GetAllInjections";
  9933. +
  9934. + // static_scripts_ is UserScriptSet
  9935. + static_scripts_.GetInjections(injections, render_frame, tab_id, run_location,
  9936. + activity_logging_enabled_);
  9937. +}
  9938. +
  9939. +void UserScriptSetManager::OnUpdateUserScripts(
  9940. + base::ReadOnlySharedMemoryRegion shared_memory) {
  9941. + if (!shared_memory.IsValid()) {
  9942. + NOTREACHED() << "Bad scripts handle";
  9943. + return;
  9944. + }
  9945. +
  9946. + UserScriptSet* scripts = NULL;
  9947. + scripts = &static_scripts_;
  9948. +
  9949. + DCHECK(scripts);
  9950. +
  9951. + // If no hosts are included in the set, that indicates that all
  9952. + // hosts were updated. Add them all to the set so that observers and
  9953. + // individual UserScriptSets don't need to know this detail.
  9954. + //const std::set<HostID>* effective_hosts = &changed_hosts;
  9955. + std::set<HostID> all_hosts;
  9956. + const std::set<HostID>* effective_hosts = &all_hosts;
  9957. +
  9958. + if (scripts->UpdateUserScripts(std::move(shared_memory), *effective_hosts,
  9959. + false /*whitelisted_only*/)) {
  9960. + for (auto& observer : observers_)
  9961. + observer.OnUserScriptsUpdated(all_hosts /* *effective_hosts*/);
  9962. + }
  9963. +}
  9964. +
  9965. +}
  9966. \ No newline at end of file
  9967. diff --git a/components/user_scripts/renderer/user_script_set_manager.h b/components/user_scripts/renderer/user_script_set_manager.h
  9968. new file mode 100755
  9969. --- /dev/null
  9970. +++ b/components/user_scripts/renderer/user_script_set_manager.h
  9971. @@ -0,0 +1,62 @@
  9972. +#ifndef USERSCRIPTS_RENDER_SET_MANAGER_H_
  9973. +#define USERSCRIPTS_RENDER_SET_MANAGER_H_
  9974. +
  9975. +#include <map>
  9976. +#include <set>
  9977. +#include <string>
  9978. +#include <vector>
  9979. +
  9980. +#include "base/macros.h"
  9981. +#include "base/memory/read_only_shared_memory_region.h"
  9982. +#include "base/observer_list.h"
  9983. +#include "content/public/renderer/render_thread_observer.h"
  9984. +#include "../common/host_id.h"
  9985. +#include "user_script_set.h"
  9986. +#include "script_injection.h"
  9987. +
  9988. +namespace user_scripts {
  9989. +
  9990. +class UserScriptSetManager : public content::RenderThreadObserver {
  9991. + public:
  9992. + class Observer {
  9993. + public:
  9994. + virtual void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) = 0;
  9995. + };
  9996. +
  9997. + UserScriptSetManager();
  9998. +
  9999. + ~UserScriptSetManager() override;
  10000. +
  10001. + void AddObserver(Observer* observer);
  10002. + void RemoveObserver(Observer* observer);
  10003. +
  10004. + // Append all injections from |static_scripts| and each of
  10005. + // |programmatic_scripts_| to |injections|.
  10006. + void GetAllInjections(
  10007. + std::vector<std::unique_ptr<ScriptInjection>>* injections,
  10008. + content::RenderFrame* render_frame,
  10009. + int tab_id,
  10010. + UserScript::RunLocation run_location);
  10011. +
  10012. +private:
  10013. + // content::RenderThreadObserver implementation.
  10014. + bool OnControlMessageReceived(const IPC::Message& message) override;
  10015. +
  10016. + base::ObserverList<Observer>::Unchecked observers_;
  10017. +
  10018. + // Handle the UpdateUserScripts extension message.
  10019. + void OnUpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory);
  10020. + //, const HostID& host_id,
  10021. + //const std::set<HostID>& changed_hosts,
  10022. + //bool whitelisted_only);
  10023. +
  10024. + // Scripts statically defined in extension manifests.
  10025. + UserScriptSet static_scripts_;
  10026. +
  10027. + // Whether or not dom activity should be logged for scripts injected.
  10028. + bool activity_logging_enabled_ = false;
  10029. +};
  10030. +
  10031. +}
  10032. +
  10033. +#endif
  10034. \ No newline at end of file
  10035. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.cc b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10036. new file mode 100755
  10037. --- /dev/null
  10038. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.cc
  10039. @@ -0,0 +1,36 @@
  10040. +#include "user_scripts_dispatcher.h"
  10041. +
  10042. +#include <stddef.h>
  10043. +
  10044. +#include <algorithm>
  10045. +#include <memory>
  10046. +#include <utility>
  10047. +
  10048. +#include "content/public/renderer/render_thread.h"
  10049. +#include "extension_frame_helper.h"
  10050. +
  10051. +namespace user_scripts {
  10052. +
  10053. +// ex ChromeExtensionsDispatcherDelegate
  10054. +UserScriptsDispatcher::UserScriptsDispatcher()
  10055. + : user_script_set_manager_observer_(this) {
  10056. + user_script_set_manager_.reset(new UserScriptSetManager());
  10057. + script_injection_manager_.reset(
  10058. + new ScriptInjectionManager(user_script_set_manager_.get()));
  10059. + user_script_set_manager_observer_.Add(user_script_set_manager_.get());
  10060. +}
  10061. +
  10062. +UserScriptsDispatcher::~UserScriptsDispatcher() {
  10063. +}
  10064. +
  10065. +void UserScriptsDispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
  10066. +}
  10067. +
  10068. +void UserScriptsDispatcher::OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) {
  10069. +}
  10070. +
  10071. +void UserScriptsDispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
  10072. + script_injection_manager_->OnRenderFrameCreated(render_frame);
  10073. +}
  10074. +
  10075. +}
  10076. \ No newline at end of file
  10077. diff --git a/components/user_scripts/renderer/user_scripts_dispatcher.h b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10078. new file mode 100755
  10079. --- /dev/null
  10080. +++ b/components/user_scripts/renderer/user_scripts_dispatcher.h
  10081. @@ -0,0 +1,48 @@
  10082. +#ifndef USERSCRIPTS_RENDER_DISPATCHER_H_
  10083. +#define USERSCRIPTS_RENDER_DISPATCHER_H_
  10084. +
  10085. +#include "user_script_set_manager.h"
  10086. +#include "script_injection_manager.h"
  10087. +
  10088. +#include <stdint.h>
  10089. +
  10090. +#include <map>
  10091. +#include <memory>
  10092. +#include <set>
  10093. +#include <string>
  10094. +#include <utility>
  10095. +#include <vector>
  10096. +
  10097. +#include "base/macros.h"
  10098. +#include "base/scoped_observer.h"
  10099. +#include "content/public/renderer/render_thread_observer.h"
  10100. +#include "content/public/renderer/render_thread.h"
  10101. +#include "../common/host_id.h"
  10102. +#include "user_script_set_manager.h"
  10103. +#include "script_injection.h"
  10104. +
  10105. +namespace user_scripts {
  10106. +
  10107. +class UserScriptsDispatcher : public content::RenderThreadObserver,
  10108. + public UserScriptSetManager::Observer {
  10109. +
  10110. + public:
  10111. + explicit UserScriptsDispatcher();
  10112. + ~UserScriptsDispatcher() override;
  10113. +
  10114. + void OnRenderThreadStarted(content::RenderThread* thread);
  10115. + void OnUserScriptsUpdated(const std::set<HostID>& changed_hosts) override;
  10116. + void OnRenderFrameCreated(content::RenderFrame* render_frame);
  10117. +
  10118. + private:
  10119. + std::unique_ptr<UserScriptSetManager> user_script_set_manager_;
  10120. +
  10121. + std::unique_ptr<ScriptInjectionManager> script_injection_manager_;
  10122. +
  10123. + ScopedObserver<UserScriptSetManager, UserScriptSetManager::Observer>
  10124. + user_script_set_manager_observer_;
  10125. +};
  10126. +
  10127. +}
  10128. +
  10129. +#endif
  10130. \ No newline at end of file
  10131. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.cc b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10132. new file mode 100755
  10133. --- /dev/null
  10134. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.cc
  10135. @@ -0,0 +1,105 @@
  10136. +#include "user_scripts_renderer_client.h"
  10137. +
  10138. +#include <memory>
  10139. +#include <utility>
  10140. +
  10141. +#include "base/logging.h"
  10142. +#include "base/lazy_instance.h"
  10143. +#include "content/public/renderer/render_frame.h"
  10144. +#include "content/public/renderer/render_thread.h"
  10145. +#include "content/public/renderer/render_frame_visitor.h"
  10146. +#include "chrome/renderer/chrome_render_thread_observer.h"
  10147. +
  10148. +#include "../common/user_scripts_features.h"
  10149. +#include "user_scripts_dispatcher.h"
  10150. +#include "extension_frame_helper.h"
  10151. +
  10152. +namespace user_scripts {
  10153. +
  10154. +// was ChromeExtensionsRendererClient
  10155. +UserScriptsRendererClient::UserScriptsRendererClient() {}
  10156. +
  10157. +UserScriptsRendererClient::~UserScriptsRendererClient() {}
  10158. +
  10159. +// static
  10160. +UserScriptsRendererClient* UserScriptsRendererClient::GetInstance() {
  10161. + static base::LazyInstance<UserScriptsRendererClient>::Leaky client =
  10162. + LAZY_INSTANCE_INITIALIZER;
  10163. + return client.Pointer();
  10164. +}
  10165. +
  10166. +void UserScriptsRendererClient::RenderThreadStarted() {
  10167. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10168. + LOG(INFO) << "UserScripts: RenderThreadStarted";
  10169. +
  10170. + content::RenderThread* thread = content::RenderThread::Get();
  10171. + dispatcher_ = std::make_unique<UserScriptsDispatcher>();
  10172. +
  10173. + dispatcher_->OnRenderThreadStarted(thread);
  10174. + thread->AddObserver(dispatcher_.get());
  10175. +}
  10176. +
  10177. +void UserScriptsRendererClient::ConfigurationUpdated() {
  10178. + if (base::FeatureList::IsEnabled(features::kEnableLoggingUserScripts))
  10179. + LOG(INFO) << "UserScripts: Configuration Updated";
  10180. +
  10181. + struct WatchFrame : public content::RenderFrameVisitor {
  10182. + bool Visit(content::RenderFrame* frame) override {
  10183. + if (frame)
  10184. + UserScriptsRendererClient::GetInstance()->RenderFrameCreated(frame, NULL);
  10185. + return true; // Continue visiting.
  10186. + }
  10187. + };
  10188. + WatchFrame visitor = {};
  10189. + content::RenderFrame::ForEach(&visitor);
  10190. +}
  10191. +
  10192. +void UserScriptsRendererClient::RenderFrameCreated(
  10193. + content::RenderFrame* render_frame,
  10194. + service_manager::BinderRegistry* registry) {
  10195. +
  10196. + auto params = ChromeRenderThreadObserver::GetDynamicParams();
  10197. + enabled_ = params.allow_userscript;
  10198. + if (!enabled_) return;
  10199. +
  10200. + if (loaded_ == false) {
  10201. + loaded_ = true;
  10202. + new user_scripts::ExtensionFrameHelper(render_frame);
  10203. + dispatcher_->OnRenderFrameCreated(render_frame);
  10204. + }
  10205. +}
  10206. +
  10207. +void UserScriptsRendererClient::RunScriptsAtDocumentStart(content::RenderFrame* render_frame) {
  10208. + if (!enabled_ || !loaded_) return;
  10209. +
  10210. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10211. + if (!frame_helper)
  10212. + return; // The frame is invisible to user scripts.
  10213. +
  10214. + frame_helper->RunScriptsAtDocumentStart();
  10215. + // |frame_helper| and |render_frame| might be dead by now.
  10216. +}
  10217. +
  10218. +void UserScriptsRendererClient::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) {
  10219. + if (!enabled_ || !loaded_) return;
  10220. +
  10221. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10222. + if (!frame_helper)
  10223. + return; // The frame is invisible to user scripts.
  10224. +
  10225. + frame_helper->RunScriptsAtDocumentEnd();
  10226. + // |frame_helper| and |render_frame| might be dead by now.
  10227. +}
  10228. +
  10229. +void UserScriptsRendererClient::RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) {
  10230. + if (!enabled_ || !loaded_) return;
  10231. +
  10232. + ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
  10233. + if (!frame_helper)
  10234. + return; // The frame is invisible to user scripts.
  10235. +
  10236. + frame_helper->RunScriptsAtDocumentIdle();
  10237. + // |frame_helper| and |render_frame| might be dead by now.
  10238. +}
  10239. +
  10240. +}
  10241. \ No newline at end of file
  10242. diff --git a/components/user_scripts/renderer/user_scripts_renderer_client.h b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10243. new file mode 100755
  10244. --- /dev/null
  10245. +++ b/components/user_scripts/renderer/user_scripts_renderer_client.h
  10246. @@ -0,0 +1,36 @@
  10247. +#ifndef USERSCRIPTS_RENDER_CLIENT_H_
  10248. +#define USERSCRIPTS_RENDER_CLIENT_H_
  10249. +
  10250. +#include <memory>
  10251. +#include <string>
  10252. +
  10253. +#include "base/macros.h"
  10254. +#include "user_scripts_dispatcher.h"
  10255. +#include "services/service_manager/public/cpp/binder_registry.h"
  10256. +
  10257. +namespace user_scripts {
  10258. +
  10259. +class UserScriptsRendererClient {
  10260. + public:
  10261. + UserScriptsRendererClient();
  10262. + ~UserScriptsRendererClient();
  10263. +
  10264. + static UserScriptsRendererClient* GetInstance();
  10265. +
  10266. + void RenderThreadStarted();
  10267. + void ConfigurationUpdated();
  10268. + void RenderFrameCreated(content::RenderFrame* render_frame,
  10269. + service_manager::BinderRegistry* registry);
  10270. + void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
  10271. + void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
  10272. + void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
  10273. +
  10274. + private:
  10275. + std::unique_ptr<UserScriptsDispatcher> dispatcher_;
  10276. + bool enabled_ = false;
  10277. + bool loaded_ = false;
  10278. +};
  10279. +
  10280. +}
  10281. +
  10282. +#endif
  10283. \ No newline at end of file
  10284. diff --git a/components/user_scripts/renderer/web_ui_injection_host.cc b/components/user_scripts/renderer/web_ui_injection_host.cc
  10285. new file mode 100755
  10286. --- /dev/null
  10287. +++ b/components/user_scripts/renderer/web_ui_injection_host.cc
  10288. @@ -0,0 +1,40 @@
  10289. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10290. +// Use of this source code is governed by a BSD-style license that can be
  10291. +// found in the LICENSE file.
  10292. +
  10293. +#include "web_ui_injection_host.h"
  10294. +#include "base/no_destructor.h"
  10295. +
  10296. +namespace {
  10297. +
  10298. +// The default secure CSP to be used in order to prevent remote scripts.
  10299. +const char kDefaultSecureCSP[] = "script-src 'self'; object-src 'self';";
  10300. +
  10301. +}
  10302. +
  10303. +WebUIInjectionHost::WebUIInjectionHost(const HostID& host_id)
  10304. + : InjectionHost(host_id),
  10305. + url_(host_id.id()) {
  10306. +}
  10307. +
  10308. +WebUIInjectionHost::~WebUIInjectionHost() {
  10309. +}
  10310. +
  10311. +const std::string* WebUIInjectionHost::GetContentSecurityPolicy() const {
  10312. + // Use the main world CSP.
  10313. + // return nullptr;
  10314. +
  10315. + // The isolated world will use its own CSP which blocks remotely hosted
  10316. + // code.
  10317. + static const base::NoDestructor<std::string> default_isolated_world_csp(
  10318. + kDefaultSecureCSP);
  10319. + return default_isolated_world_csp.get();
  10320. +}
  10321. +
  10322. +const GURL& WebUIInjectionHost::url() const {
  10323. + return url_;
  10324. +}
  10325. +
  10326. +const std::string& WebUIInjectionHost::name() const {
  10327. + return id().id();
  10328. +}
  10329. diff --git a/components/user_scripts/renderer/web_ui_injection_host.h b/components/user_scripts/renderer/web_ui_injection_host.h
  10330. new file mode 100755
  10331. --- /dev/null
  10332. +++ b/components/user_scripts/renderer/web_ui_injection_host.h
  10333. @@ -0,0 +1,28 @@
  10334. +// Copyright 2015 The Chromium Authors. All rights reserved.
  10335. +// Use of this source code is governed by a BSD-style license that can be
  10336. +// found in the LICENSE file.
  10337. +
  10338. +#ifndef USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10339. +#define USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10340. +
  10341. +#include "base/macros.h"
  10342. +#include "injection_host.h"
  10343. +
  10344. +class WebUIInjectionHost : public InjectionHost {
  10345. + public:
  10346. + WebUIInjectionHost(const HostID& host_id);
  10347. + ~WebUIInjectionHost() override;
  10348. +
  10349. + private:
  10350. + // InjectionHost:
  10351. + const std::string* GetContentSecurityPolicy() const override;
  10352. + const GURL& url() const override;
  10353. + const std::string& name() const override;
  10354. +
  10355. + private:
  10356. + GURL url_;
  10357. +
  10358. + DISALLOW_COPY_AND_ASSIGN(WebUIInjectionHost);
  10359. +};
  10360. +
  10361. +#endif // USERSCRIPTS_RENDERER_WEB_UI_INJECTION_HOST_H_
  10362. diff --git a/components/user_scripts/strings/userscripts_strings.grdp b/components/user_scripts/strings/userscripts_strings.grdp
  10363. new file mode 100755
  10364. --- /dev/null
  10365. +++ b/components/user_scripts/strings/userscripts_strings.grdp
  10366. @@ -0,0 +1,55 @@
  10367. +<?xml version="1.0" encoding="utf-8"?>
  10368. +<grit-part>
  10369. +
  10370. + <!-- Preferences -->
  10371. + <message name="IDS_PREFS_USERSCRIPTS_SETTINGS"
  10372. + desc="."
  10373. + formatter_data="android_java">
  10374. + User Scripts
  10375. + </message>
  10376. +
  10377. + <message name="IDS_OPTION_USERSCRIPT_FLAG" desc="." formatter_data="android_java">
  10378. + Activate User Scripts
  10379. + </message>
  10380. +
  10381. + <message name="IDS_OPTION_USERSCRIPT_FLAG_ON" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10382. + ON
  10383. + </message>
  10384. + <message name="IDS_OPTION_USERSCRIPT_FLAG_OFF" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10385. + OFF
  10386. + </message>
  10387. +
  10388. + <message name="IDS_ADD_SCRIPT" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10389. + Add script
  10390. + </message>
  10391. + <message name="IDS_SCRIPTS_LIST_DESCRIPTION" desc="." formatter_data="android_java">
  10392. + Experimental support for Greasemonkey-style user scripts.
  10393. + </message>
  10394. +
  10395. + <message name="IDS_SCRIPTS_ITEM_VERSION" desc="." formatter_data="android_java">
  10396. + Version:
  10397. + </message>
  10398. + <message name="IDS_SCRIPTS_ITEM_FILENAME" desc="." formatter_data="android_java">
  10399. + File:
  10400. + </message>
  10401. + <message name="IDS_SCRIPTS_ITEM_URL" desc="." formatter_data="android_java">
  10402. + Url:
  10403. + </message>
  10404. +
  10405. + <message name="IDS_SCRIPTS_VIEW_SOURCE" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10406. + View source
  10407. + </message>
  10408. +
  10409. + <message name="IDS_ASK_TO_INSTALL" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10410. + Only install user scripts that you have verified are secure, user scripts can steal your credentials and data.
  10411. +
  10412. +Do you want to install <ph name="FILE">%s</ph>?
  10413. + </message>
  10414. + <message name="IDS_YES" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10415. + Yes
  10416. + </message>
  10417. + <message name="IDS_NO" desc=". [CHAR-LIMIT=32]" formatter_data="android_java">
  10418. + No
  10419. + </message>
  10420. +
  10421. +</grit-part>
  10422. \ No newline at end of file
  10423. diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
  10424. --- a/tools/gritsettings/resource_ids.spec
  10425. +++ b/tools/gritsettings/resource_ids.spec
  10426. @@ -475,6 +475,12 @@
  10427. "components/autofill/core/browser/autofill_address_rewriter_resources.grd":{
  10428. "includes": [2880]
  10429. },
  10430. + "components/user_scripts/renderer/resources/user_scripts_renderer_resources.grd": {
  10431. + "includes": [6000],
  10432. + },
  10433. + "components/user_scripts/browser/resources/browser_resources.grd": {
  10434. + "includes": [6020],
  10435. + },
  10436. # END components/ section.
  10437. # START ios/ section.
  10438. --
  10439. 2.17.1